Microservices Architecture trong Java

1. Nguyên tắc Thiết kế Microservices

1.1 Single Responsibility

  • Mỗi service chịu trách nhiệm cho một business capability
  • Độc lập về data và logic
  • Loose coupling, high cohesion

1.2 Service Autonomy

@Service
public class OrderService {
    private final OrderRepository orderRepository;
    private final EventPublisher eventPublisher;

    public Order createOrder(Order order) {
        // Validate và xử lý business logic
        Order savedOrder = orderRepository.save(order);

        // Publish event cho các service khác
        eventPublisher.publish(new OrderCreatedEvent(savedOrder));

        return savedOrder;
    }
}

1.3 Database per Service

@Configuration
public class OrderDataSourceConfig {
    @Bean
    @ConfigurationProperties("spring.datasource.orders")
    public DataSourceProperties orderDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean
    public DataSource orderDataSource() {
        return orderDataSourceProperties()
            .initializeDataSourceBuilder()
            .build();
    }
}

2. Service Discovery và Registration

2.1 Netflix Eureka

@SpringBootApplication
@EnableEurekaServer
public class ServiceRegistryApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceRegistryApplication.class, args);
    }
}

// Client configuration
@SpringBootApplication
@EnableDiscoveryClient
public class MicroserviceApplication {
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

2.2 Service-to-Service Communication

@Service
public class OrderServiceClient {
    private final RestTemplate restTemplate;

    public Order getOrder(Long orderId) {
        return restTemplate.getForObject(
            "http://order-service/api/orders/{id}",
            Order.class,
            orderId
        );
    }
}

3. API Gateway

3.1 Spring Cloud Gateway

@Configuration
public class GatewayConfig {
    @Bean
    public RouteLocator customRouteLocator(
            RouteLocatorBuilder builder) {
        return builder.routes()
            .route("order_service", r -> r
                .path("/api/orders/**")
                .filters(f -> f
                    .rewritePath("/api/(?<segment>.*)", "/${segment}")
                    .addRequestHeader("X-Gateway-Source", "gateway")
                    .circuitBreaker(config -> config
                        .setName("orderServiceCircuitBreaker")
                        .setFallbackUri("forward:/fallback")))
                .uri("lb://order-service"))
            .build();
    }
}

3.2 Security at Gateway

@Configuration
@EnableWebFluxSecurity
public class GatewaySecurityConfig {
    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(
            ServerHttpSecurity http) {
        return http
            .csrf().disable()
            .authorizeExchange()
                .pathMatchers("/public/**").permitAll()
                .anyExchange().authenticated()
            .and()
            .oauth2ResourceServer()
                .jwt()
            .and()
            .build();
    }
}

4. Circuit Breaker Pattern

4.1 Resilience4j Implementation

@Configuration
public class Resilience4jConfig {
    @Bean
    public CircuitBreakerConfig circuitBreakerConfig() {
        return CircuitBreakerConfig.custom()
            .failureRateThreshold(50)
            .waitDurationInOpenState(Duration.ofMillis(1000))
            .slidingWindowSize(2)
            .build();
    }

    @Bean
    public Customizer<Resilience4jCircuitBreakerFactory> defaultCustomizer() {
        return factory -> factory.configureDefault(
            id -> new Resilience4jConfigBuilder(id)
                .circuitBreakerConfig(circuitBreakerConfig())
                .build());
    }
}

@Service
public class OrderService {
    @CircuitBreaker(name = "orderService", fallbackMethod = "fallback")
    public Order getOrder(Long id) {
        return orderRepository.findById(id)
            .orElseThrow(() -> new OrderNotFoundException(id));
    }

    public Order fallback(Long id, Exception ex) {
        return new Order(); // Fallback response
    }
}

5. Event-Driven Architecture

5.1 Apache Kafka Integration

@Configuration
public class KafkaConfig {
    @Bean
    public ProducerFactory<String, Event> 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, Event> kafkaTemplate() {
        return new KafkaTemplate<>(producerFactory());
    }
}

@Service
public class OrderEventPublisher {
    private final KafkaTemplate<String, Event> kafkaTemplate;

    public void publishOrderCreated(Order order) {
        OrderCreatedEvent event = new OrderCreatedEvent(order);
        kafkaTemplate.send("order-events", event);
    }
}

@Service
public class OrderEventConsumer {
    @KafkaListener(topics = "order-events", groupId = "order-service")
    public void handleOrderEvent(OrderCreatedEvent event) {
        // Process the event
    }
}

6. Distributed Tracing

6.1 Spring Cloud Sleuth với Zipkin

@Configuration
public class TracingConfig {
    @Bean
    public Sampler defaultSampler() {
        return Sampler.ALWAYS_SAMPLE;
    }
}

@RestController
public class OrderController {
    private static final Logger log = 
        LoggerFactory.getLogger(OrderController.class);

    @GetMapping("/api/orders/{id}")
    public Order getOrder(@PathVariable Long id) {
        log.info("Fetching order {}", id);
        return orderService.getOrder(id);
    }
}

7. Configuration Management

7.1 Spring Cloud Config

@Configuration
@EnableConfigServer
public class ConfigServerConfig {
    // Configuration Server setup
}

// Client configuration
@RefreshScope
@Configuration
public class OrderServiceConfig {
    @Value("${order.service.timeout}")
    private int timeout;

    @Value("${order.service.retryCount}")
    private int retryCount;
}

8. Service Mesh Integration

8.1 Istio Configuration

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: order-service
spec:
  hosts:
  - order-service
  http:
  - route:
    - destination:
        host: order-service
        subset: v1
      weight: 90
    - destination:
        host: order-service
        subset: v2
      weight: 10

9. Monitoring và Observability

9.1 Prometheus và Grafana Integration

@Configuration
public class MetricsConfig {
    @Bean
    MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
        return registry -> registry.config()
            .commonTags("application", "order-service");
    }
}

@Service
public class OrderMetrics {
    private final MeterRegistry registry;

    public void recordOrderProcessingTime(long duration) {
        registry.timer("order.processing.time")
            .record(duration, TimeUnit.MILLISECONDS);
    }

    public void incrementOrderCounter() {
        registry.counter("order.created").increment();
    }
}

10. Testing Strategies

10.1 Contract Testing với Spring Cloud Contract

@SpringBootTest(webEnvironment = RANDOM_PORT)
public class OrderControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @Test
    public void shouldCreateOrder() {
        mockMvc.perform(post("/api/orders")
            .contentType(MediaType.APPLICATION_JSON)
            .content(orderJson))
            .andExpect(status().isCreated())
            .andExpect(jsonPath("$.id").exists());
    }
}

// Contract Definition
Contract.make {
    request {
        method 'POST'
        url '/api/orders'
        body([
            customerId: $(consumer(regex('[0-9]+')))
        ])
        headers {
            contentType('application/json')
        }
    }
    response {
        status 201
        body([
            id: $(producer(regex('[0-9]+')))
        ])
        headers {
            contentType('application/json')
        }
    }
}

11. Deployment Strategies

11.1 Blue-Green Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service-blue
spec:
  replicas: 3
  selector:
    matchLabels:
      app: order-service
      version: blue
  template:
    metadata:
      labels:
        app: order-service
        version: blue
    spec:
      containers:
      - name: order-service
        image: order-service:1.0
---
apiVersion: v1
kind: Service
metadata:
  name: order-service
spec:
  selector:
    app: order-service
    version: blue
  ports:
  - port: 80
    targetPort: 8080

12. Security Considerations

12.1 OAuth2 và JWT

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/api/public/**").permitAll()
                .antMatchers("/api/**").authenticated()
            .and()
            .oauth2ResourceServer()
                .jwt();
    }
}

13. Best Practices và Guidelines

13.1 Service Design Guidelines

  • Keep services small and focused
  • Design for failure
  • Use asynchronous communication when possible
  • Implement proper logging and monitoring
  • Follow the 12-factor app principles

13.2 API Design Guidelines

  • Use REST maturity model
  • Implement proper versioning
  • Use proper HTTP methods and status codes
  • Implement proper documentation
  • Follow API security best practices

14. References

  • Building Microservices by Sam Newman
  • Spring Microservices in Action by John Carnell
  • Production-Ready Microservices by Susan Fowler
  • Domain-Driven Design by Eric Evans