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