Java 微服务开发指南
目录
服务发现
Eureka
java
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
@SpringBootApplication
@EnableEurekaClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}Consul
java
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
@Configuration
public class ConsulConfig {
@Bean
public ConsulProperties consulProperties() {
ConsulProperties properties = new ConsulProperties();
properties.setHost("localhost");
properties.setPort(8500);
return properties;
}
}配置中心
Spring Cloud Config
java
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
@SpringBootApplication
@EnableConfigClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}Nacos
java
@SpringBootApplication
@EnableNacosConfig
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
@NacosConfigurationProperties(prefix = "user", autoRefreshed = true)
public class UserProperties {
private String name;
private String email;
// getters and setters
}服务治理
熔断器
java
@SpringBootApplication
@EnableCircuitBreaker
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
@Service
public class UserService {
@HystrixCommand(fallbackMethod = "getUserFallback")
public User getUser(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
}
public User getUserFallback(Long id) {
return new User(id, "Default User", "[email protected]");
}
}限流器
java
@Configuration
public class RateLimiterConfig {
@Bean
public RateLimiter rateLimiter() {
return RateLimiter.create(100.0); // 每秒100个请求
}
}
@RestController
public class UserController {
@Autowired
private RateLimiter rateLimiter;
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
if (rateLimiter.tryAcquire()) {
return userService.getUser(id);
}
throw new TooManyRequestsException();
}
}API 网关
Spring Cloud Gateway
java
@SpringBootApplication
@EnableGateway
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("user_service", r -> r.path("/users/**")
.uri("lb://user-service"))
.route("order_service", r -> r.path("/orders/**")
.uri("lb://order-service"))
.build();
}
}消息队列
RabbitMQ
java
@Configuration
public class RabbitConfig {
@Bean
public Queue userQueue() {
return new Queue("user.queue");
}
@Bean
public Exchange userExchange() {
return ExchangeBuilder.directExchange("user.exchange")
.durable(true)
.build();
}
@Bean
public Binding userBinding() {
return BindingBuilder.bind(userQueue())
.to(userExchange())
.with("user.routing.key")
.noargs();
}
}
@Service
public class UserService {
@Autowired
private RabbitTemplate rabbitTemplate;
public void createUser(User user) {
userRepository.save(user);
rabbitTemplate.convertAndSend(
"user.exchange",
"user.routing.key",
user
);
}
}Kafka
java
@Configuration
public class KafkaConfig {
@Bean
public ProducerFactory<String, User> producerFactory() {
Map<String, Object> config = new HashMap<>();
config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
config.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
config.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
return new DefaultKafkaProducerFactory<>(config);
}
@Bean
public KafkaTemplate<String, User> kafkaTemplate() {
return new KafkaTemplate<>(producerFactory());
}
}
@Service
public class UserService {
@Autowired
private KafkaTemplate<String, User> kafkaTemplate;
public void createUser(User user) {
userRepository.save(user);
kafkaTemplate.send("user-topic", user);
}
}分布式追踪
Sleuth + Zipkin
java
@SpringBootApplication
@EnableSleuth
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
@Configuration
public class SleuthConfig {
@Bean
public Sampler defaultSampler() {
return Sampler.ALWAYS_SAMPLE;
}
}
@Service
public class UserService {
@Autowired
private Tracer tracer;
public User getUser(Long id) {
Span span = tracer.createSpan("getUser");
try {
return userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
} finally {
tracer.close(span);
}
}
}容器化部署
Docker
dockerfile
FROM openjdk:11-jre-slim
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]Kubernetes
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
spec:
replicas: 3
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: user-service:latest
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: prod
- name: EUREKA_CLIENT_SERVICEURL_DEFAULTZONE
value: http://eureka-server:8761/eureka/
---
apiVersion: v1
kind: Service
metadata:
name: user-service
spec:
selector:
app: user-service
ports:
- port: 80
targetPort: 8080
type: ClusterIP监控告警
Spring Boot Actuator
java
@SpringBootApplication
@EnableActuator
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
@Configuration
public class ActuatorConfig {
@Bean
public MeterRegistry meterRegistry() {
return new SimpleMeterRegistry();
}
@Bean
public TimedAspect timedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
}Prometheus
java
@Configuration
public class PrometheusConfig {
@Bean
public MeterRegistry prometheusRegistry() {
return new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
}
@Bean
public TimedAspect timedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
}
@Service
public class UserService {
@Autowired
private MeterRegistry registry;
@Timed(value = "user.service.time", description = "Time taken to get user")
public User getUser(Long id) {
Counter counter = registry.counter("user.service.calls");
counter.increment();
return userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
}
}