Ir para o conteúdo

Emerson Amorim

Software Architecture

Microsserviços com Java 21 e Spring Boot 3: Clean Architecture, DDD e Event-Driven Architecture

Como estruturar microsserviços em Java 21 e Spring Boot 3 com Clean Architecture, DDD e eventos — limites, contratos e operação.

Por Emerson Amorim16 min de leitura

Microsserviços em Java 21 e Spring Boot 3 só sustentam escala se os limites de domínio forem reais. Clean Architecture e DDD organizam o interior; eventos coordenam o exterior sem acoplar ciclos de vida.

Comece pelos limites de contexto

Antes de criar repositórios, desenhe bounded contexts e linguagem ubíqua. Um serviço por tabela é fragmentação, não arquitetura. Um serviço por capacidade de negócio com dono claro é o alvo.

Clean Architecture no módulo

adapters/web ──► application ──► domain
adapters/db  ──► application ──► domain
adapters/mq  ──► application ──► domain
domain ← application ← adapters (web, persistence, messaging).
Caso de uso sem dependência de framework
public final class OpenAccountService implements OpenAccountUseCase {
  private final AccountRepository accounts;
  private final DomainEventPublisher events;

  public OpenAccountService(AccountRepository accounts, DomainEventPublisher events) {
    this.accounts = accounts;
    this.events = events;
  }

  @Override
  public AccountId handle(OpenAccountCommand cmd) {
    Account account = Account.open(cmd.customerId(), cmd.product());
    accounts.save(account);
    events.publish(account.pullEvents());
    return account.id();
  }
}

O que Java 21 muda na prática

  • Virtual threads para I/O-bound sob Tomcat/Netty com cuidado em pooling de JDBC
  • Records e pattern matching para contratos internos mais claros
  • Sequenced collections e APIs modernas sem reinventar utilitários

Spring Boot 3 e observabilidade

Boot 3 assume Jakarta EE e encaixa bem com Micrometer Observation e tracing OpenTelemetry. Padronize correlation id na borda e propague em mensagens.

Event-Driven Architecture

Use eventos de domínio para fatos que já ocorreram. Evite orquestração síncrona em cadeia entre muitos serviços. Outbox pattern evita dual-write entre banco e broker.

Outbox mínimo
@Transactional
public void saveAndOutbox(Account account, DomainEvent event) {
  accountRepository.save(account);
  outboxRepository.insert(OutboxMessage.from(event));
}

Testes e limites

  • Testes de domínio sem Spring
  • Contratos consumer-driven nas APIs
  • Não distribua transações XA como primeira opção
  • Evite shared database entre contextos