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
- Documentação Oficial Spring Boot — Guia completo de configuração e funcionalidades do Spring Boot para microserviços.
- Spring Cloud Config Reference — Documentação oficial sobre configuração centralizada para ambientes distribuídos.
- Resilience4j Documentation — Guia prático de padrões de resiliência como Circuit Breaker e Retry para Java.
- Spring Cloud Gateway Reference — Documentação oficial do gateway de API com roteamento, filtros e rate limiting.
- Kubernetes Documentation - Deployments — Guia oficial de orquestração de containers com Kubernetes.
- Spring Cloud Sleuth Documentation — Documentação para rastreamento distribuído e logging em microserviços.