Microserviços com Spring Boot e Java

1. Fundamentos da Arquitetura de Microserviços

A arquitetura de microserviços representa uma abordagem moderna para desenvolvimento de software, onde cada serviço é independente, possui responsabilidade única e se comunica de forma leve com os demais. Diferentemente do monólito tradicional, onde toda a lógica reside em um único processo, os microserviços permitem escalabilidade horizontal, deploy independente e manutenção simplificada.

Princípios de design:
- Responsabilidade única: cada serviço resolve um problema específico
- Acoplamento fraco: serviços se comunicam via APIs bem definidas
- Isolamento de falhas: um serviço com problema não derruba o sistema inteiro

Quando adotar microserviços?
- Equipes grandes trabalhando em paralelo
- Necessidade de escalar componentes específicos
- Ciclos de deploy frequentes

Armadilhas comuns:
- Complexidade de rede e latência
- Gerenciamento de transações distribuídas
- Testes de integração complexos

2. Configuração Inicial com Spring Boot

Criar um projeto Spring Boot com Spring Initializr é o primeiro passo. As dependências essenciais incluem:

  • Spring Web
  • Spring Data JPA
  • Spring Cloud Config Client
  • Eureka Discovery Client
  • Spring Actuator

Estrutura de pacotes recomendada:

com.exemplo.pedidos/
├── controller/
│   └── PedidoController.java
├── service/
│   └── PedidoService.java
├── repository/
│   └── PedidoRepository.java
├── model/
│   └── Pedido.java
├── dto/
│   └── PedidoRequest.java
├── config/
│   └── AppConfig.java
└── PedidosApplication.java

Configuração application.yml para ambientes distribuídos:

server:
  port: 8081

spring:
  application:
    name: servico-pedidos
  datasource:
    url: jdbc:postgresql://localhost:5432/pedidos
    username: ${DB_USER}
    password: ${DB_PASS}
  jpa:
    hibernate:
      ddl-auto: update

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

O Spring Cloud Config centraliza configurações em um repositório Git, permitindo alterações sem reinicializar serviços.

3. Comunicação entre Serviços

REST com Spring Web

Usando WebClient (reativo e não bloqueante):

@Service
public class ClienteService {

    private final WebClient webClient;

    public ClienteService(WebClient.Builder builder) {
        this.webClient = builder.baseUrl("http://servico-clientes").build();
    }

    public Mono<Cliente> buscarCliente(Long id) {
        return webClient.get()
                .uri("/clientes/{id}", id)
                .retrieve()
                .bodyToMono(Cliente.class);
    }
}

Padrões de Resiliência com Resilience4j

Circuit Breaker:

@CircuitBreaker(name = "servico-pagamentos", fallbackMethod = "fallbackPagamento")
public Pagamento processarPagamento(Pedido pedido) {
    return pagamentoClient.realizar(pedido);
}

public Pagamento fallbackPagamento(Pedido pedido, Throwable t) {
    log.error("Falha ao processar pagamento. Usando fallback.", t);
    return new Pagamento(pedido.getId(), Status.PENDENTE);
}

Descoberta de Serviços com Eureka

@Bean
@LoadBalanced
public WebClient.Builder loadBalancedWebClientBuilder() {
    return WebClient.builder();
}

4. Persistência e Transações Distribuídas

Banco de Dados por Serviço

Cada microserviço gerencia seu próprio banco de dados. Configuração de múltiplas fontes:

@Configuration
public class DataSourceConfig {

    @Bean
    @Primary
    @ConfigurationProperties("spring.datasource.pedidos")
    public DataSource pedidosDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties("spring.datasource.estoque")
    public DataSource estoqueDataSource() {
        return DataSourceBuilder.create().build();
    }
}

Sagas Coreografadas com Kafka

@Service
public class SagaOrquestrador {

    @KafkaListener(topics = "pedido-criado")
    public void processarPedidoCriado(PedidoEvent event) {
        // Reservar estoque
        kafkaTemplate.send("reservar-estoque", event);
    }

    @KafkaListener(topics = "estoque-reservado")
    public void processarEstoqueReservado(PedidoEvent event) {
        // Processar pagamento
        kafkaTemplate.send("processar-pagamento", event);
    }

    @KafkaListener(topics = "pagamento-falhou")
    public void compensarEstoque(PedidoEvent event) {
        kafkaTemplate.send("cancelar-reserva-estoque", event);
    }
}

5. Observabilidade e Monitoramento

Rastreamento Distribuído com Spring Cloud Sleuth

@Slf4j
@Service
public class PedidoService {

    public Pedido criarPedido(PedidoRequest request) {
        log.info("Criando pedido: {}", request);
        // O Sleuth adiciona automaticamente traceId e spanId
        return pedidoRepository.save(new Pedido(request));
    }
}

Métricas com Micrometer e Prometheus

@Configuration
public class MetricaConfig {

    @Bean
    public MeterRegistry meterRegistry() {
        return new SimpleMeterRegistry();
    }

    @Bean
    public TimedAspect timedAspect(MeterRegistry registry) {
        return new TimedAspect(registry);
    }
}

Health Checks com Spring Actuator

@Component
public class DatabaseHealthIndicator implements HealthIndicator {

    @Override
    public Health health() {
        try {
            // Verifica conexão com banco
            return Health.up().withDetail("database", "PostgreSQL").build();
        } catch (Exception e) {
            return Health.down(e).build();
        }
    }
}

6. Segurança e Autenticação Distribuída

Autenticação com JWT

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(authz -> authz
                .requestMatchers("/api/public/**").permitAll()
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
        return http.build();
    }
}

Gateway de API com Spring Cloud Gateway

spring:
  cloud:
    gateway:
      routes:
        - id: servico-pedidos
          uri: lb://servico-pedidos
          predicates:
            - Path=/api/pedidos/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20

7. Deploy e Orquestração

Dockerfile Otimizado

FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8081
ENTRYPOINT ["java", "-jar", "app.jar"]

Kubernetes Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: servico-pedidos
spec:
  replicas: 3
  selector:
    matchLabels:
      app: servico-pedidos
  template:
    metadata:
      labels:
        app: servico-pedidos
    spec:
      containers:
      - name: servico-pedidos
        image: registry.exemplo.com/servico-pedidos:v1
        ports:
        - containerPort: 8081
        env:
        - name: DB_USER
          valueFrom:
            secretKeyRef:
              name: db-credentials
              key: username
        livenessProbe:
          httpGet:
            path: /actuator/health
            port: 8081

Pipeline CI/CD com Testes de Contrato

# .github/workflows/deploy.yml
name: CI/CD Pipeline
on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run contract tests
        run: mvn test -Pcontract-tests

  deploy:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - name: Build and push Docker image
        run: |
          docker build -t servico-pedidos:${{ github.sha }} .
          docker push registry.exemplo.com/servico-pedidos:${{ github.sha }}
      - name: Deploy to Kubernetes
        run: kubectl set image deployment/servico-pedidos servico-pedidos=registry.exemplo.com/servico-pedidos:${{ github.sha }}

A arquitetura de microserviços com Spring Boot e Java oferece uma base sólida para sistemas distribuídos modernos. Combinando princípios de design, ferramentas de observabilidade, segurança e orquestração, é possível construir soluções escaláveis e resilientes. O ecossistema Spring Cloud fornece abstrações poderosas que simplificam desafios como descoberta de serviços, configuração centralizada e tolerância a falhas, permitindo que desenvolvedores foquem na lógica de negócio.

Referências