Skip to content

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));
    }
}

启航团队技术文档