Skip to content

Spring e Spring Boot

Visão organizada do ecossistema Spring, com foco em Spring Boot — o framework mais usado para APIs e microsserviços em Java. A página segue uma trilha didática: do conceito e do ambiente, passando pela injeção de dependência e configuração, até a camada web. Conceitos de teoria geral (HTTP, REST, camadas, SOLID) ficam nas páginas específicas: Backend, Boas Práticas e Padrões Arquiteturais.

O que é o Spring Boot

Definição: Spring Boot

Framework do ecossistema Spring que simplifica a criação e a execução de aplicações Java: reduz a configuração repetitiva e oferece convenções sensatas, de modo que a aplicação nasce pronta para rodar, com menos código de infraestrutura.

Spring x Spring Boot. O Spring Framework fornece a base e os recursos do ecossistema (IoC, DI, MVC, transações); o Spring Boot configura e inicializa a aplicação sobre essa base. O Boot é a "porta de entrada": os starters conectam os módulos e cada módulo adiciona funcionalidades.

Os quatro pilares do Spring Boot:

Recurso O que faz
Autoconfiguração Analisa as dependências do projeto e cria automaticamente as configurações prováveis, com base em condições (ex.: se há driver de banco no classpath, configura o DataSource)
Starters Pacotes de dependências coordenadas (ex.: spring-boot-starter-web) que facilitam adicionar funcionalidades seguindo boas práticas do ecossistema
Servidor embutido A aplicação roda como um único JAR com Tomcat embutido — não é preciso instalar servidor separado, o que facilita deploy e distribuição
Recursos prontos para produção Métricas, health checks e configuração externa já integrados

Onde é usado: APIs REST, back-ends de aplicações, microsserviços, sistemas corporativos e aplicações web.

O ecossistema Spring

Módulo Papel
Spring Framework Base: IoC, DI, MVC para web, suporte a transações
Spring Boot Configuração rápida; produz aplicações prontas para execução e para produção
Spring Initializr Gerador oficial de projetos; permite escolher dependências e cria a estrutura inicial
Spring Data Simplifica o acesso a dados com repositórios prontos (JPA, JDBC), reduz código repetitivo e integra vários bancos
Spring Security Autenticação, autorização, proteção de endpoints e integração com provedores de identidade (ex.: OAuth2)
Spring Cloud Recursos para sistemas distribuídos: configuração centralizada, descoberta de serviços, resiliência e tolerância a falhas, escalabilidade em nuvem

Preparando o ambiente

Item Recomendação
Java Java 17 ou superior (JDK confiável); verifique com java -version
IDE IntelliJ IDEA, Eclipse/STS ou VS Code
Build tool Maven ou Gradle — prefira o wrapper do próprio projeto (./mvnw, ./gradlew)
Java base Classes e interfaces, collections, exceções, anotações
Web base HTTP e URL; métodos (GET, POST, PUT, DELETE); status (200, 404, 500); JSON
Banco de dados SQL básico; H2 para estudo, PostgreSQL em projetos reais

Checklist de verificação: JDK configurada, IDE encontra o SDK, wrapper executa sem erro (java --version, ./mvnw -v, ./gradlew -v).

Criando o projeto com o Spring Initializr

O Spring Initializr (start.spring.io) é a ferramenta oficial para gerar a estrutura inicial em poucos passos:

  1. Acesse start.spring.io.
  2. Escolha o projeto (Maven ou Gradle — ambos são suportados).
  3. Escolha a linguagem (Java) e uma versão estável (17 ou 21).
  4. Preencha os metadados: group (ex.: com.exemplo), artifact (ex.: minha-api), name e package.
  5. Adicione as dependências (ex.: Spring Web para a primeira API); outras podem vir depois.
  6. Clique em Generate (baixa um .zip) e extraia.
  7. Importe o projeto na IDE e aguarde a resolução das dependências.
  8. Execute a classe Application (com main) e procure a mensagem Started no console.

Estrutura do projeto

com.exemplo.cadastro
├── CadastroApplication.java      <- classe principal (pacote raiz)
├── controller/
├── service/
├── repository/
└── model/
Local Conteúdo
src/main/java Código principal, organizado em pacotes (controllers, services, domínio)
src/main/resources application.properties / .yaml, arquivos estáticos, templates, imagens, CSS
src/test/java Testes automatizados; espelha os pacotes principais (unidade e integração)
pom.xml / build.gradle Arquivo de build: declara plugins e dependências, define versão e tarefas
target/ (ou build/) Saída gerada pela compilação (.class, libs, artefato); não editar, pode ser recriada

Boas práticas de pacotes: use domínio invertido (com.exemplo.cadastro), evite o pacote default e mantenha a classe principal acima dos demais pacotes (é a partir dela que o Spring varre os componentes).

Maven e Gradle

Ambos automatizam dependências, compilação, testes e empacotamento (geram o JAR executável).

Maven Gradle
Configuração pom.xml (XML) build.gradle (script)
Característica Ciclo de vida padronizado, previsível Tarefas flexíveis
Comando típico ./mvnw package ./gradlew build
  • O wrapper (mvnw/gradlew) acompanha o projeto e padroniza a versão da ferramenta em todos os ambientes.
  • O Spring Boot gerencia as versões das dependências para que sejam compatíveis entre si (por isso o starter não exige número de versão).
  • Empacote com ./mvnw package e execute com java -jar app.jar.
  • Qual escolher? Maven é previsível; Gradle é flexível; siga o padrão da equipe.

A anotação @SpringBootApplication

Marca a classe principal e reúne três recursos:

Anotação Função
@Configuration Permite declarar configurações e definir beans no contexto
@EnableAutoConfiguration Ativa as configurações automáticas, considerando as dependências e respeitando as propriedades (application.properties)
@ComponentScan Procura componentes (@Component, @Controller, @Service…) a partir do pacote raiz e os registra como beans
@SpringBootApplication
public class CadastroApplication {
    public static void main(String[] args) {          // ponto de entrada padrão do Java
        SpringApplication.run(CadastroApplication.class, args);
    }
}

SpringApplication.run() cria o ApplicationContext, inicializa a aplicação e carrega os beans. Resumo: uma anotação reúne configuração, autoconfiguração e varredura de componentes — "menos configuração, mais produtividade".

IoC e injeção de dependência

O problema: criar dependências com new dentro das classes aumenta o acoplamento.

Definição: Inversão de Controle (IoC) e Injeção de Dependência (DI)

IoC: o contêiner (e não a própria classe) controla a criação e a ligação dos objetos. DI: a classe recebe a dependência já pronta, em vez de criá-la. O contêiner principal do Spring é o ApplicationContext, que registra os beans. (Ver também o padrão Dependency Injection.)

@Service
public class PedidoService {
    private final Pagamento pagamento;                // campo final: imutável

    public PedidoService(Pagamento pagamento) {       // injeção por construtor (recomendada)
        this.pagamento = pagamento;
    }
}
  • Por construtor é a forma recomendada: explicita os requisitos e permite campos final.
  • Dependa de interfaces (o contrato), não da implementação.
  • Benefícios: modularidade, testes simples e troca localizada de implementações.
  • Evite: new espalhado, campos estáticos e injeção por campo (@Autowired direto no atributo), que esconde dependências e dificulta o teste.

Beans e estereótipos

Definição: Bean

Objeto criado e gerenciado pelo contêiner do Spring. Os estereótipos são anotações que registram a classe como bean e revelam o seu papel.

Anotação Papel
@Component Componente genérico, detectado pelo component scan
@Service Camada de serviço: regra de negócio
@Repository Acesso a dados: persistência e integração com o banco
@Controller Entrada da camada web: recebe requisições e devolve uma visão ou resposta
@RestController Controller especializado que devolve o corpo da resposta (geralmente JSON) — usado em APIs REST
@Bean Registra manualmente o retorno de um método; usado em classes @Configuration (ex.: bibliotecas de terceiros)

Configuração externa

Permite mudar o ambiente sem recompilar a aplicação.

Mecanismo Uso
.properties Formato chave=valor (server.port=8081)
.yaml Formato hierárquico; a indentação é significativa
@Value Injeta uma propriedade pontual: @Value("${server.port}") private int porta;
@ConfigurationProperties Agrupa propriedades com tipagem e validação, mapeando várias de uma vez em uma classe (prefix = "app") — preferível para configuração estruturada
Perfis (profiles) Separam configuração por ambiente (dev, test, prod); ativados com spring.profiles.active=dev
Variáveis de ambiente Sobrescrevem application.properties/yml; usadas no deploy (Docker, servidores, CI/CD)
server:
  port: 8081
spring:
  profiles:
    active: dev

Segredos

Mantenha senhas fora do Git. Use variáveis de ambiente ou um gerenciador de segredos, para evitar vazamento de credenciais.

Spring Web MVC

Definição: MVC (Model-View-Controller)

Padrão que separa responsabilidades: Model (dados/entidades de domínio), View (apresenta a resposta: Thymeleaf, JSP, ou uma API que devolve JSON) e Controller (recebe a requisição, processa e chama a camada de serviço).

O Spring Web MVC vem com o starter spring-boot-starter-web, que também traz um servidor embutido (Tomcat). O DispatcherServlet é o ponto único de entrada: recebe a requisição, resolve a rota (@RequestMapping) e a encaminha ao controller correto.

flowchart LR
    C["Cliente"] --> D["DispatcherServlet"]
    D --> K["Controller"]
    K --> S["Service"]
    S --> K
    K --> R["Resposta<br/>(JSON ou view)"]
    R --> C

@RestController: de métodos Java a endpoints HTTP

@RestController indica que a classe é um controller REST; os métodos retornam o corpo da resposta (JSON). @RequestMapping define o caminho base; cada verbo HTTP tem sua anotação:

Anotação Verbo Uso típico
@GetMapping GET Consulta (leitura de dados)
@PostMapping POST Criação de novos recursos
@PutMapping PUT Atualização de recursos existentes
@DeleteMapping DELETE Remoção de recursos
@RestController
@RequestMapping("/usuarios")
public class UsuarioController {

    @GetMapping
    public List<Usuario> listar() { /* ... */ }

    @PostMapping
    public Usuario criar(@RequestBody Usuario usuario) { /* ... */ }

    @PutMapping("/{id}")
    public Usuario atualizar(@PathVariable Long id, @RequestBody Usuario usuario) { /* ... */ }

    @DeleteMapping("/{id}")
    public void remover(@PathVariable Long id) { /* ... */ }
}

Fluxo: requisição HTTP (GET /usuarios) → método do controller → resposta JSON.

Rotas, métodos HTTP e status

Cada verbo HTTP comunica uma intenção. Teoria completa de HTTP/REST em Backend; aqui, o mapeamento típico em uma API Spring:

Verbo Intenção Exemplo Status usual
GET Buscar dados; não altera o estado GET /usuarios/1 200 OK
POST Criar um recurso; dados no corpo POST /usuarios 201 Created
PUT Substituir/atualizar todo o recurso (dados completos) PUT /usuarios/1 200 OK
PATCH Alteração parcial (só os campos modificados) PATCH /usuarios/1 200 OK
DELETE Remover um recurso (usar com atenção) DELETE /usuarios/1 204 No Content

Outros status comuns: 404 Not Found (não encontrado) e 500 Internal Server Error (erro no servidor). A URL identifica o recurso e representa o caminho dele.

Boas práticas de rotas: nomes no plural (/usuarios), rotas claras e objetivas e um padrão consistente em toda a API.

DTOs

Definição: DTO (Data Transfer Object)

Objeto usado para entrada ou saída de dados da API. Carrega apenas os dados que a API precisa expor ou receber, mantendo a camada de API desacoplada do modelo de domínio: DTO não é entidade.

  • Entrada: dados recebidos do cliente (ex.: corpo de POST/PUT).
  • Saída: a resposta pública da API, contendo só o necessário.
  • Segurança: não exponha campos internos (senha, roles, IDs sensíveis); controle o que é devolvido na resposta.
  • Mapeamento: converte-se entidade → DTO manualmente ou com ferramentas (ex.: MapStruct).
  • record (Java 16+) é a forma enxuta para DTOs imutáveis simples.
public record UsuarioResponse(Long id, String nome) {}

UsuarioResponse dto = new UsuarioResponse(usuario.getId(), usuario.getNome());

Resultado: contrato da API claro, manutenção mais fácil, mais segurança e integração mais estável.

Validação de dados

Rejeite entradas inválidas antes da regra de negócio, na borda da aplicação (DTO, formulário, API), usando o Bean Validation (starter spring-boot-starter-validation).

Anotação Efeito
@Valid Ativa a validação dos campos do objeto; usada em parâmetros do controller (ex.: @RequestBody)
@NotNull Não aceita null; para campos obrigatórios
@NotBlank Não aceita texto vazio nem só espaços; para String
@Size Limita tamanho de texto/coleção/array (@Size(max = 80) String nome;)
@Email Valida o formato de e-mail (@Email String email;)
public record UsuarioRequest(
    @NotBlank @Size(max = 80) String nome,
    @NotBlank @Email String email) {}

@PostMapping
public Usuario criar(@Valid @RequestBody UsuarioRequest dados) { /* ... */ }

O BindingResult dá acesso aos erros de validação e permite verificar quais campos falharam. Retorne mensagens claras, informando qual campo está inválido e por quê. Evite deixar dados inválidos chegarem à regra de negócio.

Spring Data JPA

Definição: JPA, Hibernate e Spring Data JPA

JPA é a especificação Java de persistência objeto-relacional; o Hibernate é a implementação mais usada (converte objetos em SQL e cuida do mapeamento). O Spring Data JPA constrói sobre eles para dar acesso a dados com menos código, baseado em convenções.

  • Starter: spring-boot-starter-data-jpa (traz Spring Data, JPA e Hibernate); basta adicioná-lo ao pom.xml ou build.gradle.
  • Entity: classe Java mapeada para uma tabela (@Entity, @Id, @Column) — representa o domínio.
  • Repository: interface que define as operações de acesso a dados; estende JpaRepository e o Spring Data a implementa automaticamente.
  • CRUD pronto: save, findById, findAll, delete…
  • Transação: garante uma operação consistente no banco; usa @Transactional em serviços ou métodos e faz rollback automático em caso de erro.
public interface UsuarioRepository extends JpaRepository<Usuario, Long> {}

Entidades JPA

@Entity
@Table(name = "usuarios")
public class Usuario {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String nome;
    private String email;

    protected Usuario() {}        // construtor sem argumentos (exigido pelo JPA)
    // getters/setters conforme necessário
}
Elemento Papel
@Entity Indica que a classe é persistida pelo JPA e mapeada para uma tabela
@Id Define o atributo que é a chave primária
@GeneratedValue Gera o identificador automaticamente (IDENTITY, SEQUENCE, AUTO)
Atributos Viram colunas; use tipos compatíveis com o banco (String, Long, LocalDate)
Construtor padrão Necessário para o JPA criar instâncias (via reflexão)
@Table Personaliza nome da tabela, esquema e outras opções
Encapsulamento Atributos privados, getters/setters quando necessário; regras de negócio dentro da entidade

Relacionamentos JPA

Anotação Relação Exemplo
@OneToOne Exatamente uma outra entidade (uni ou bidirecional) Usuário ↔ Perfil
@OneToMany Uma entidade ligada a várias Cliente → Pedidos
@ManyToOne Muitas entidades ligadas a uma; o lado "muitos" mantém a referência Pedidos → Cliente
@ManyToMany Muitas com muitas, normalmente via tabela de junção Alunos ↔ Cursos
  • Dono do relacionamento: escolha o lado dono e use mappedBy no lado inverso, mantendo consistência e evitando atualizações duplicadas.
  • fetch: define como os relacionados são carregados — LAZY (sob demanda, recomendado) ou EAGER (junto com a entidade; use com cautela).
  • cascade: propaga operações (PERSIST, MERGE, REMOVE) automaticamente; use com cuidado para evitar deleções indesejadas.
  • Modele os relacionamentos conforme o domínio do negócio, de forma consciente.

(Relacionamentos entre tabelas na teoria: Modelagem de Dados.)

Tratamento de exceções

Problema: uma exceção não tratada gera resposta confusa e pode expor detalhes técnicos. Falhas também fazem parte do contrato da API.

Recurso Função
@ExceptionHandler Trata um erro específico dentro de um controller, convertendo a exceção em resposta HTTP adequada
@RestControllerAdvice Centraliza o tratamento de exceções da aplicação e evita repetição entre controllers
@ResponseStatus Define o código de status da resposta (400, 404, 500…)
Erro de domínio Exceção que representa regra de negócio inválida (e-mail já cadastrado, saldo insuficiente)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public class RegraDeNegocioException extends RuntimeException {
    public RegraDeNegocioException(String mensagem) { super(mensagem); }
}

@RestControllerAdvice
public class ApiErrors {
    @ExceptionHandler(RegraDeNegocioException.class)
    public ResponseEntity<String> tratar(RegraDeNegocioException e) {
        return ResponseEntity.badRequest().body(e.getMessage());
    }
}

Retorne mensagem útil e compreensível sem expor detalhes internos; registre em log o necessário para diagnóstico (tipo da exceção, mensagem, contexto) e evite dados sensíveis nos logs. Tratar exceções de forma padronizada melhora a experiência do cliente e a manutenção.

Camadas da aplicação e primeiro CRUD

flowchart LR
    C["Cliente"] --> K["Controller<br/>entrada HTTP"]
    K --> S["Service<br/>regras de negócio"]
    S --> R["Repository<br/>acesso a dados"]
    R --> B[("Banco de dados")]
    B --> R
    R --> S
    S --> K
    K -->|JSON| C
Camada Responsabilidade Exemplo
Controller Recebe requisições HTTP, valida/converte dados, chama o service, devolve a resposta (JSON) @RestController, @GetMapping("/usuarios")
Service Regras de negócio, coordena operações, chama o repository, valida e trata @Service class UsuarioService
Repository Persistência; estende JpaRepository e fornece métodos prontos interface UsuarioRepository extends JpaRepository<Usuario, Long>
Entity Modelo de dados persistido (JPA), com os atributos da tabela e relacionamentos @Entity @Table(name = "usuarios")
DTO Formato dos dados que entram e saem da API; evita expor entidades diretamente record UsuarioDTO(String nome, String email)

CRUD completo

Operação Requisição Retorno
Create POST /usuarios (dados no corpo) 201 Created
Read GET /usuarios ou GET /usuarios/{id} 200 OK com JSON
Update PUT /usuarios/{id} 200 OK
Delete DELETE /usuarios/{id} 204 No Content

A camada Service em detalhe

O Service contém a lógica de negócio e orquestra as operações, mantendo o controller fino. É um bean gerenciado (@Service, especialização de @Component), injetado por construtor — o que facilita os testes, pois pode ser mockado. Chama o repository para acessar dados (separação negócio ≠ persistência) e devolve um objeto, lista ou DTO, podendo lançar exceções de negócio:

@Service
public class UsuarioService {
    private final UsuarioRepository repository;

    public UsuarioService(UsuarioRepository repository) {
        this.repository = repository;
    }

    public UsuarioDTO encontrarPorId(Long id) {
        return repository.findById(id)
                .map(this::converter)
                .orElseThrow(() -> new RegraDeNegocioException("Usuário não encontrado"));
    }
}

Camada Repository em detalhe

O repository abstrai o acesso ao banco (JPA/Hibernate por baixo), trabalha com entidades e permite trocar de banco sem alterar o código da aplicação. É uma interface Java sem implementação manual, detectada automaticamente pelo Spring (@Repository), com a nomenclatura NomeDaEntidadeRepository.

public interface ProdutoRepository extends JpaRepository<Produto, Long> {}

O JpaRepository<Entidade, TipoDoId> já traz o CRUD pronto, sem escrever SQL:

Método Função
save(produto) Salva (insere ou atualiza) um registro
findById(id) Busca por ID
findAll() Lista todos
deleteById(id) Remove por ID
count() Retorna a quantidade

Também oferece diversas consultas e paginação prontas.

Consultas com Spring Data

Estratégia Como funciona Quando usar
Derived query (consulta derivada) O Spring cria a consulta pelo nome do método (findBy…), com operadores And, Or, Like, Between… Consultas simples
@Query Consulta personalizada em JPQL ou SQL nativo; parâmetros nomeados (@Param) ou posicionais (?1) Consultas complexas, mais controle
// derived query: filtros por palavras-chave no nome do método
List<Usuario> findByNome(String nome);
List<Usuario> findByStatus(String status);
List<Usuario> findByNomeContaining(String nome);
List<Usuario> findByDataBetween(LocalDate ini, LocalDate fim);

// ordenação pelo nome do método ou por Sort
List<Usuario> findAllByOrderByNomeAsc();
List<Usuario> findByStatus(String status, Sort sort);

// @Query com parâmetro nomeado
@Query("SELECT u FROM Usuario u WHERE u.nome = :nome")
List<Usuario> buscarPorNome(@Param("nome") String nome);

@Query("SELECT p FROM Produto p WHERE p.preco > :preco")
List<Produto> findProdutosCaros(@Param("preco") BigDecimal preco);

Os parâmetros podem ser vários tipos (String, Long, LocalDate…) e também Pageable e Sort. Fluxo: aplicação → repository (derived ou @Query) → banco → resultados.

Paginação e ordenação

Buscar dados em partes evita respostas enormes e melhora a performance.

Elemento Papel
Pageable Interface com as informações de paginação e ordenação; parâmetro dos métodos do repository; criada manualmente ou recebida da requisição (?page=0&size=10&sort=nome)
Page<T> Representa uma página de resultados: a lista de dados + metadados da paginação (total de páginas/elementos), facilitando a navegação
Tamanho da página Quantos registros por página (Pageable.ofSize(10))
Número da página Qual página retornar; a contagem começa em 0 (PageRequest.of(0, 10))
Sort Define a ordenação por um ou mais campos, crescente ou decrescente; combinável com Pageable
Sort sort = Sort.by("nome").ascending();
Pageable pageable = PageRequest.of(0, 10, sort);     // página 0, 10 itens, por nome
Page<Usuario> pagina = usuarioRepository.findAll(pageable);

Configuração na prática: arquivos, perfis e banco de dados

Complementa a visão geral de configuração externa.

application.properties x application.yml: o primeiro usa chave=valor (simples, padrão do Spring Boot); o segundo é hierárquico, mais organizado e legível — muito usado em projetos reais.

spring.application.name=meu-projeto
server.port=8080
spring:
  application:
    name: meu-projeto
server:
  port: 8080

A porta padrão é 8080; altere com server.port para evitar conflitos.

Perfis de ambiente

Perfil Característica típica
dev Desenvolvimento: logs detalhados, banco em memória (H2), configurações flexíveis, facilita testes locais
test Testes automatizados (integração e unitários): geralmente banco em memória; isola do ambiente de desenvolvimento e produção
prod Produção: configuração otimizada, logs em nível adequado (INFO/WARN), banco real (PostgreSQL, MySQL), prioriza segurança e estabilidade
  • Arquivos separados por perfil: application-dev.properties, application-test.properties, application-prod.properties.
  • Ativação: em application.properties (spring.profiles.active=dev), por variável de ambiente ou por argumento da JVM (-Dspring.profiles.active=prod).

Conexão com o banco de dados

spring.datasource.url=jdbc:postgresql://localhost:5432/meubanco
spring.datasource.username=usuario
spring.datasource.password=senha
Item Detalhe
URL JDBC Indica banco, host, porta e nome da base, no formato do driver
Usuário spring.datasource.username; deve ter as permissões necessárias
Senha spring.datasource.password; em produção, use variáveis de ambiente ou um cofre de segredos
Driver Implementação JDBC do banco, adicionada como dependência (ex.: org.postgresql:postgresql); o Spring Boot detecta e configura a conexão automaticamente
Migrações Flyway ou Liquibase versionam o esquema e aplicam mudanças na inicialização, mantendo o banco consistente entre ambientes (spring.flyway.enabled=true, spring.flyway.locations=classpath:db/migration)

Testes no Spring Boot

Ver também a teoria em Qualidade.

Recurso Uso
JUnit 5 Framework de testes (@Test, @BeforeEach, @AfterEach)
Teste unitário Testa uma pequena parte do código (ex.: um serviço), com foco na lógica de negócio, rápido e isolado; usa mocks para as dependências
@SpringBootTest Carrega o contexto completo da aplicação; para testes de integração com todos os beans como em ambiente real — mais lento que o unitário
MockMvc Testa controllers (camada web) simulando requisições HTTP, sem subir o servidor real; verifica status, corpo e headers
Cobertura Mede quanto do código é testado (ferramentas como JaCoCo); ajuda a achar partes sem teste
@Test
void deveCalcularTotal() {
    assertEquals(100, servico.calcular(50, 50));
}

@SpringBootTest
class MinhaAplicacaoTest { /* ... */ }

mockMvc.perform(get("/usuarios"))
       .andExpect(status().isOk())
       .andExpect(jsonPath("$.size()").value(1));

Documentação da API (OpenAPI e Swagger)

Definição: OpenAPI e Swagger UI

OpenAPI é o padrão para descrever APIs REST (JSON/YAML): endpoints, modelos, parâmetros e respostas. O Swagger UI é a interface web interativa gerada a partir dessa descrição (/swagger-ui.html), que permite explorar e testar os endpoints no navegador.

  • Exibe todos os endpoints, métodos HTTP, descrições, parâmetros e códigos de resposta.
  • Mostra exemplos de requisição e resposta (corpo em JSON), facilitando a integração de outros sistemas.
  • Contratos: descreve a estrutura dos dados (DTOs) e os schemas de entrada e saída, com anotações como @Schema e @Operation, mantendo a documentação sempre atualizada com o código.
@Schema(description = "Dados do usuário")
public class UsuarioDTO {
    private String nome;
    private String email;
}

Segurança da aplicação (Spring Security)

Visão geral de autenticação/autorização na teoria em Segurança. Adicione o starter spring-boot-starter-security.

Conceito Resumo
Autenticação Verifica a identidade (quem é): login/senha, JWT, OAuth2; integra com UserDetailsService e AuthenticationManager; suporta vários provedores
Autorização Define o que o usuário pode fazer: papéis (roles) ou autoridades (authorities), por endpoint ou método; controle de acesso baseado em papéis (RBAC)
Senhas Nunca em texto plano; use BCryptPasswordEncoder configurado como bean, para criptografar e validar no login
Endpoints protegidos Regras de acesso com HttpSecurity; libera os públicos (/login, /public) e protege os sensíveis
Filtros O Spring Security funciona como uma cadeia de filtros executada antes do controller; filtros personalizados (JWT, logging, auditoria) entram na ordem desejada na SecurityFilterChain
@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

SecurityFilterChain e regras de acesso

A SecurityFilterChain (que substitui a antiga configuração por WebSecurityConfigurerAdapter) configura a cadeia de filtros, define quais requisições são protegidas e personaliza autenticação e autorização:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests(auth -> auth
            .requestMatchers("/public/**").permitAll()
            .requestMatchers("/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated());
    return http.build();
}
Recurso Configuração
Regras de acesso authorizeHttpRequests: liberar ou proteger URLs, métodos HTTP e perfis (roles/authorities)
Login formLogin habilita o formulário padrão; personaliza URL de login, sucesso e erro; redireciona após login bem-sucedido
Logout Encerra a sessão; personaliza a URL e a página após o logout; invalida a sessão e limpa os cookies
CSRF Protege contra falsificação de requisição; habilitado por padrão em aplicações web, usa tokens para validar requisições que alteram estado (POST/PUT/DELETE); pode ser desabilitado só quando necessário (ex.: APIs stateless)

Definição: CSRF (Cross-Site Request Forgery)

Ataque que induz o navegador autenticado do usuário a enviar uma requisição indesejada ao sistema. A defesa usual é um token exigido nas requisições que alteram estado. Em APIs stateless com token no cabeçalho (ex.: JWT) é comum desabilitar o CSRF; em aplicações com sessão/cookies ele deve permanecer ativo. Ver também as considerações de segurança do OAuth 2.0 em Segurança.

JWT e tokens

Fluxo típico: o usuário envia as credenciais ao endpoint de login → a aplicação valida (ex.: no banco) → se corretas, gera o token JWT e o devolve ao cliente → o cliente o envia nas requisições seguintes.

Definição: JWT (JSON Web Token)

String codificada em Base64 que carrega informações (claims) sobre o usuário e é assinada digitalmente para evitar adulteração. Usada para autenticar e autorizar requisições. (Estrutura detalhada — JWS/JWE — em Segurança.)

Elemento Detalhe
Claims Informações dentro do token: padrão (sub, exp, iat) ou personalizadas (ID, nome, roles, permissões); permitem à aplicação tomar decisões de autorização
Expiração O token tem tempo de vida (exp); a aplicação deve verificar a data. Para sessões longas, usar refresh token
Bearer O token vai no cabeçalho HTTP: Authorization: Bearer <token>; a aplicação extrai, valida assinatura e expiração e identifica o usuário autenticado
{ "sub": "123", "name": "João", "roles": "USER", "iat": 1710000000, "exp": 1710003600 }

(exp - iat = 3600 → válido por 1 hora.) Em uma API Spring, a validação costuma ser feita por um filtro (ex.: JwtAuthenticationFilter) adicionado antes do UsernamePasswordAuthenticationFilter na SecurityFilterChain.

Roles e permissões

Conceito Detalhe
ROLE_USER Papel padrão de usuários autenticados; funcionalidades básicas, geralmente operações de leitura
ROLE_ADMIN Papel com privilégios elevados: gerenciar usuários, configurações e dados sensíveis
Prefixo ROLE_ O Spring Security espera o prefixo em papéis (hasRole('ADMIN') procura ROLE_ADMIN)
@PreAuthorize Restringe o acesso a métodos com expressões SpEL, avaliadas antes da execução; comum em controllers e services
Acesso negado Sem permissão, o Spring Security devolve HTTP 403 (Forbidden); é possível personalizar a resposta com mensagem clara
@PreAuthorize("hasRole('ADMIN')")
public void deletarUsuario() { /* lógica de exclusão */ }

Princípio do menor privilégio

Conceda apenas as permissões necessárias; evite dar privilégios de administrador a todos. Reduz o risco de acessos indevidos ("dê apenas o necessário, nada além"). Diferença de status: 401 = não autenticado; 403 = autenticado, mas sem permissão.

CORS e integração com front-end

Definição: CORS (Cross-Origin Resource Sharing)

Mecanismo do navegador que controla quais origens podem acessar a API. Uma origem é definida por protocolo + domínio + porta (ex.: http://localhost:3000, https://meuapp.com). Sem CORS configurado, o navegador bloqueia requisições de outra origem.

  • Preflight: para métodos como PUT/DELETE ou headers personalizados, o navegador envia antes uma requisição OPTIONS; o servidor deve responder com os cabeçalhos CORS corretos.
  • Métodos permitidos: defina só os que o front-end usa (GET, POST, PUT, DELETE, OPTIONS); evite liberar o desnecessário.
  • Headers: permita os que o front-end envia (Content-Type, Authorization, X-Requested-With); headers incorretos fazem o navegador bloquear a requisição.
  • Integração com React: o front-end React geralmente roda em http://localhost:3000; configure a API para permitir essa origem com @CrossOrigin no controller ou uma configuração global.
@RestController
@RequestMapping("/api/produtos")
@CrossOrigin(origins = "http://localhost:3000",
             allowedHeaders = {"Content-Type", "Authorization"})
public class ProdutoController { /* endpoints */ }

Detalhes gerais de CORS na teoria: Backend.

Configuração avançada e injeção de dependência

Complementa IoC e injeção de dependência e Beans e estereótipos.

Classes de configuração Java. @Configuration marca a classe com métodos de configuração e substitui o XML de configuração do Spring: permite definir beans de forma programática, com suporte a condições, perfis e importação de outras configurações. @Bean indica que o método devolve um bean gerenciado, com controle sobre nome, escopo e dependências — útil para integrar bibliotecas externas e objetos complexos.

@Configuration
@Import(BancoConfig.class)          // combina configurações
public class AppConfig {
    @Bean
    public MeuServico meuServico() { return new MeuServico(); }
}

Modularidade: separe configurações em classes específicas, combine com @Import, aplique @Profile para ambientes diferentes e organize em módulos para facilitar manutenção e reuso.

Mais sobre injeção:

  • Além do construtor, existe a injeção por @Autowired (em construtores, setters ou campos); o Spring resolve pelo tipo. Prefira o construtor: garante imutabilidade das dependências e deixa o código mais claro e testável.
  • É possível injetar interfaces, implementações e beans customizados.
  • Baixo acoplamento: os componentes dependem de interfaces (contratos), o que facilita trocar implementações — é o Princípio da Inversão de Dependência (DIP) do SOLID.
  • Testes fáceis: permite injetar mocks e instanciar o serviço manualmente em teste unitário (new Service(mockRepo)), deixando os testes isolados, rápidos e confiáveis.

Logs

O Spring Boot usa o SLF4J (fachada de logging) com Logback como implementação padrão (já incluído). Com Lombok, basta @Slf4j na classe.

@Slf4j
@Service
public class PedidoService {
    public void criar() {
        log.info("Pedido criado");
        log.warn("Estoque baixo para o produto: {}", idProd);
        log.error("Erro ao processar o pedido", ex);
    }
}
Nível Uso
TRACE / DEBUG Detalhes de diagnóstico, para desenvolvimento
INFO Informações gerais; indica que o fluxo normal está funcionando
WARN Situação de atenção: algo inesperado que não impede a execução; ajuda a prevenir problemas críticos
ERROR Erros que afetam a execução; essenciais para diagnóstico em produção

Os níveis definem a gravidade da mensagem e ajudam a filtrar e analisar o que acontece na aplicação. Use placeholders ({}) em vez de concatenar texto e não registre dados sensíveis. Observabilidade em geral: ver SRE.

Actuator e monitoramento

O Spring Boot Actuator expõe endpoints para monitorar a saúde, as métricas e as informações da aplicação.

Endpoint O que mostra
/actuator/health Saúde da aplicação e das dependências (UP/DOWN): banco, mensageria, disco; aceita health checks customizados
/actuator/metrics Métricas (CPU, memória, threads, requisições…); integra com Prometheus e Grafana; permite métricas próprias
/actuator/info Nome, versão, descrição e ambiente da aplicação (configurável no application.yml)
env, beans… Outros endpoints, habilitáveis ou desabilitáveis
management.endpoints.web.exposure.include=health,info,metrics

Em produção

Exponha apenas os endpoints necessários, restrinja o acesso com autenticação, exponha-os em redes internas quando possível e combine com Prometheus, Grafana e alertas para monitorar continuamente a disponibilidade.

Arquitetura limpa com Spring

Princípios na teoria em Padrões Arquiteturais (Clean Architecture e Hexagonal). Aplicadas a um projeto Spring:

Camada Papel Dependências
Domínio Regras de negócio, entidades e objetos de valor; independente de frameworks e tecnologias externas Nenhuma
Casos de uso Lógica da aplicação; orquestra o fluxo entre domínio e interfaces/infraestrutura; testável facilmente Domínio
Interfaces Expõem a aplicação ao mundo externo (controllers); convertem requisições em chamadas de casos de uso e tratam DTOs, validações e mapeamentos; sem regra de negócio Casos de uso
Infraestrutura Detalhes técnicos (banco, APIs externas, JPA, JDBC, HTTP); implementa as interfaces (ex.: repositórios); substituível sem impactar domínio e casos de uso Interfaces definidas no núcleo

Regra de ouro: as dependências apontam para dentro (das camadas externas para as internas); o domínio não depende de nada — aplicação do DIP. Facilita manutenção, testes e evolução. Fluxo: Controller → Use Case → Repository.

Microsserviços com Spring

Teoria em Microsserviços. Características que o ecossistema Spring (Spring Cloud) ajuda a implementar:

Característica Detalhe
Serviço independente Cada serviço tem uma responsabilidade; desenvolvido, implantado e escalado de forma independente; baixo acoplamento; times e tecnologias diferentes por serviço
Comunicação Síncrona (REST, gRPC) ou assíncrona (mensageria, eventos); use APIs bem definidas (contratos); prefira a assíncrona para maior resiliência; implemente tratamento de falhas (retry, timeout, circuit breaker)
Banco por serviço Cada serviço tem seu próprio banco; evita acoplamento de dados; comunicação por APIs ou eventos (nunca acesso direto ao banco de outro serviço)
Escalabilidade Escala só os serviços que precisam; lida melhor com picos; melhora o uso de recursos; facilita evolução e entrega contínua
Descoberta de serviços Serviços se registram em um registro (Eureka, Consul); localização dinâmica das instâncias; balanceamento de carga e resiliência; adequada a ambientes dinâmicos (contêineres, Kubernetes)
flowchart LR
    C["Cliente"] --> G["API Gateway"]
    G --> S1["Serviço A"]
    G --> S2["Serviço B"]
    G --> S3["Serviço C"]
    S1 -.->|registro| D["Descoberta<br/>(Eureka/Consul)"]
    S2 -.-> D
    S3 -.-> D

Comunicação entre serviços

Recurso Função
REST HTTP com endpoints REST e JSON; simples, padronizado, amplamente adotado
Feign Client Cliente HTTP declarativo (Spring Cloud OpenFeign): abstrai chamadas REST com interfaces
Timeout Tempo máximo de espera por uma resposta; evita bloqueio indefinido
Retry Tenta novamente em falhas temporárias (ex.: indisponibilidade de rede), com número de tentativas e intervalo configuráveis
Circuit Breaker Evita chamadas a serviços indisponíveis: abre o circuito após um número de falhas, permite recuperação gradual e evita efeito cascata (ex.: Resilience4j)
@FeignClient(name = "pedido-service", url = "${pedido.url}")
public interface PedidoClient {
    @GetMapping("/pedidos/{id}")
    PedidoDTO buscarPorId(@PathVariable Long id);
}

Mensageria

Comunicação assíncrona, confiável e escalável entre aplicações. Teoria de arquitetura orientada a eventos em Event-Driven Architecture.

Elemento Papel
Evento Fato que aconteceu no sistema (pedido criado, pagamento aprovado); carrega dados relevantes no payload; permite desacoplar os serviços
Produtor Publica mensagens na fila ou exchange, convertendo os dados para um formato (ex.: JSON); não precisa saber quem consumirá
Fila Armazena temporariamente as mensagens e garante a entrega mesmo que o consumidor esteja indisponível; segue FIFO (primeiro a entrar, primeiro a sair); implementada com RabbitMQ, Kafka ou Amazon SQS
Consumidor Recebe e processa as mensagens de forma assíncrona; pode haver vários consumidores em paralelo; no Spring Boot usa-se @RabbitListener
Processamento assíncrono A mensagem é tratada independentemente da requisição original, melhorando performance e escalabilidade; ideal para tarefas demoradas (e-mail, relatório, integração externa); facilita resiliência com retry e DLQ (dead letter queue, fila de erros)
flowchart LR
    P["Produtor"] --> F[("Fila")]
    F --> C["Consumidor"]

Cache

Armazena dados em memória para respostas mais rápidas: evita consultas desnecessárias ao banco e melhora a escalabilidade. Ideal para dados que mudam pouco ou são acessados com muita frequência. Fluxo: requisição → cache → resposta.

Recurso Função
@Cacheable O resultado do método é guardado em cache; na próxima chamada com a mesma chave, devolve o valor do cache sem executar o método
@CacheEvict Remove dados do cache quando o dado é alterado ou removido (uma chave específica ou o cache inteiro), mantendo a consistência
@CachePut Atualiza o cache com o resultado do método (sem pular a execução)
Invalidação Remove ou atualiza dados desatualizados; essencial quando os dados mudam na base; por chave, por padrão ou por tempo de expiração (TTL) — evita devolver informação inconsistente
Redis Cache distribuído e de alta performance, muito usado com Spring Boot; suporta estruturas ricas (strings, hashes, listas); permite compartilhar cache entre várias instâncias
@Cacheable("produtos")
public Produto buscarPorId(Long id) { /* busca no banco */ }

@CacheEvict(value = "produtos", key = "#id")
public void remover(Long id) { /* remove do banco e invalida o cache */ }

(Habilite com @EnableCaching e o starter de cache.)

Upload e download de arquivos

Aspecto Detalhe
MultipartFile Representa o arquivo enviado (multipart/form-data); permite acessar nome, tipo, tamanho e bytes
Armazenamento Sistema de arquivos local, serviço de nuvem (ex.: AWS S3) ou banco (BLOB); defina uma estratégia de organização (pastas, nomes únicos)
Validação Valide tipo (imagem, PDF…), extensão e tipo MIME (content type), impeça envio de arquivos maliciosos e valide o tamanho máximo
Tamanho máximo spring.servlet.multipart.max-file-size=10MB e max-request-size=10MB; trate exceções para arquivos maiores com mensagem clara
Download Devolva o arquivo como resposta HTTP, com ResponseEntity, MediaType adequado e o nome no cabeçalho Content-Disposition
Resposta de upload Mensagem de sucesso + dados do arquivo (nome, tamanho, URL)
@PostMapping("/upload")
public ResponseEntity<String> enviar(@RequestParam("arquivo") MultipartFile arquivo) { /* ... */ }

Envio de e-mails

O JavaMailSender é a interface do Spring para enviar e-mails (simples e com anexos), abstraindo o JavaMail e configurada automaticamente a partir das propriedades SMTP.

spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=seu@email.com
spring.mail.password=${MAIL_PASSWORD}
  • SMTP: protocolo de envio; requer host, porta, usuário e senha; pode usar TLS/SSL. (Mantenha a senha em variável de ambiente.)
  • Assunto: título claro e objetivo, pode ter informações dinâmicas (message.setSubject("Bem-vindo!")).
  • Corpo: texto simples ou HTML (message.setText("...", true) — o true indica HTML), com variáveis e dados dinâmicos.
  • Anexos: com MimeMessageHelper (helper.addAttachment("relatorio.pdf", new File(...))); úteis para relatórios, documentos e imagens.

Tarefas agendadas

Execução automática de métodos em horários ou intervalos definidos, sem threads manuais ou schedulers externos — útil para tarefas recorrentes (limpeza, envio de e-mails, relatórios, sincronizações).

  • Ative com @EnableScheduling na aplicação e anote o método com @Scheduled; o método deve ser void e sem parâmetros.
  • cron: expressão com segundo, minuto, hora, dia do mês, mês e dia da semana (@Scheduled(cron = "0 0 * * * *") → toda hora cheia).
  • Intervalo: fixedRate (executa em intervalos fixos, independente da duração do método), fixedDelay (considera o tempo de execução anterior) e initialDelay, em milissegundos.

Concorrência

Por padrão o Spring executa as tarefas agendadas em uma única thread (uma de cada vez). Evite sobreposição se a tarefa demorar; para paralelismo, configure um TaskScheduler com pool de threads; em aplicações com várias instâncias, considere locks distribuídos (Redis, banco de dados) para que só uma execute a tarefa.

Containers e Docker com Spring Boot

Teoria completa em Containers (Docker).

Conceito Papel
Dockerfile Define como criar a imagem: imagem base, dependências, arquivos copiados, comando de inicialização; permite versões reprodutíveis
Imagem Pacote imutável com a aplicação e suas dependências; criada do Dockerfile; pode ser versionada em um registry (ex.: Docker Hub) e gerar vários contêineres
Contêiner Instância em execução de uma imagem; isola a aplicação do ambiente host; leve, rápido de iniciar e descartável
Porta Expõe o contêiner ao mundo externo com mapeamento host:container (-p 8080:8080)
Ambiente igual A aplicação roda do mesmo jeito em dev, teste e produção — evita o "funciona na minha máquina" e facilita CI/CD
docker build -t app .
docker run -p 8080:8080 app

CI/CD para aplicações Spring Boot

Pipeline típico: commit → build → teste → deploy, executado a cada commit ou pull request.

Etapa Descrição
Build Compila, resolve dependências (Maven/Gradle), gera o artefato (JAR/WAR), pode rodar análise estática; deve ser reprodutível e automatizado
Testes Unitários, de integração, de segurança e cobertura; falha nos testes interrompe o pipeline
Pipeline Orquestra as etapas, definido como código (Jenkins, GitHub Actions, GitLab CI…); pode ter ambientes dev, homologação e produção
Deploy Publica no destino (Kubernetes, Docker, servidor/nuvem); automatizado e seguro; suporta estratégias como blue/green e canary release
Feedback rápido Informa falhas de build, testes e deploy o mais cedo possível; notificações por e-mail, Slack, GitHub

Performance e boas práticas

Prática Detalhe
Paginação Não carregue grandes volumes na memória; use Pageable/Page e retorne só o necessário
Índices Crie índices nas colunas mais consultadas (evita full scan); analise o plano de execução; em JPA: @Table(indexes = @Index(name = "idx_email", columnList = "email"))
Cache Para dados que mudam pouco (@Cacheable, @CachePut, @CacheEvict); reduz a carga no banco
Logs adequados Níveis corretos, informações relevantes, evitar logs excessivos em produção
Código limpo SOLID, DRY e KISS; métodos pequenos com uma responsabilidade; nomes descritivos
Medir antes de otimizar Identifique os gargalos reais com métricas, logs e monitoramento (Actuator, Spring Boot Metrics, APM); evite otimizações desnecessárias

Deploy em nuvem

Fluxo: Build → Deploy → Monitorar.

Item Recomendação
Build Maven ou Gradle; prefira JAR executável; execute os testes antes (./mvnw clean package, ./gradlew clean build); build reprodutível e versionado
Variáveis de ambiente Externalize configurações sensíveis; não commite segredos no Git; use um gerenciador de segredos (AWS Secrets Manager, Azure Key Vault) — ex.: DB_PASSWORD=${DB_PASSWORD}, SPRING_PROFILES_ACTIVE=prod
Banco gerenciado Amazon RDS, Azure Database, Google Cloud SQL; URL/usuário/senha por variáveis de ambiente; backups automáticos; regras de acesso e VPC (security group)
Logs Centralize (CloudWatch, Azure Monitor, Google Cloud Logging); níveis adequados; inclua o traceId para rastreamento
Domínio Domínio próprio, DNS (Route 53, Azure DNS, Cloud DNS), HTTPS com certificado SSL (Let's Encrypt ou gerenciado) e redirecionamento HTTP → HTTPS

Conceitos de nuvem e modelos de contratação em Nuvem.

Kubernetes com Spring Boot

Orquestração de contêineres para aplicações escaláveis e resilientes (teoria em Containers (Docker)).

Recurso Função
Pod Menor unidade de execução; pode conter um ou mais contêineres que compartilham rede e armazenamento; ideal para a aplicação Spring Boot
Deployment Gerencia múltiplas réplicas de Pods; atualizações contínuas (rolling update); recupera automaticamente Pods que falham; facilita o escalonamento
Service Expõe a aplicação dentro ou fora do cluster; IP estável e balanceamento de carga; tipos ClusterIP, NodePort, LoadBalancer
ConfigMap Armazena configurações não sensíveis, separando-as da imagem; consumidas como variável de ambiente ou arquivo
Secret Armazena dados sensíveis (senhas, tokens); codificados em base64 (e protegidos por controle de acesso — base64 não é criptografia)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: minha-app
  template:
    metadata:
      labels:
        app: minha-app
    spec:
      containers:
        - name: app
          image: minha-app:latest

Aplique os manifestos no cluster com kubectl apply -f app.yaml (vale para Pod, Deployment, Service, ConfigMap e Secret).

Transações

@Transactional indica que um método (ou classe/interface) deve executar dentro de uma transação, com commit e rollback gerenciados automaticamente. Configurações: readOnly, propagation, isolation, timeout.

@Transactional
public void salvarDados() {
    // operações de banco de dados
}
Conceito Significado
Atomicidade "Tudo ou nada": todas as operações são executadas por completo ou nenhuma; se uma falha, a transação inteira é desfeita; evita dados em estado parcial
Commit Confirma as alterações de forma permanente, automaticamente ao fim da transação sem erros; os dados ficam visíveis a outras transações; após o commit não é possível desfazer
Rollback Desfaz todas as alterações da transação; acontece automaticamente quando uma exceção não capturada é lançada; mantém a integridade; configurável por tipo de exceção
Consistência A transação leva o banco de um estado válido a outro, respeitando regras de negócio e restrições (constraints)

Atomicidade e consistência são duas das quatro propriedades ACID (atomicidade, consistência, isolamento e durabilidade).

Detalhe do rollback

Por padrão o Spring faz rollback apenas para exceções não verificadas (RuntimeException e Error). Para exceções verificadas (checked), configure @Transactional(rollbackFor = Exception.class). Evite também capturar a exceção dentro do método transacional sem relançá-la, pois o rollback não ocorrerá.

Resiliência (Resilience4j)

Aplicação mais estável, tolerante a falhas e com degradação controlada. O Resilience4j é uma biblioteca leve que integra com o Spring Boot e fornece timeout, retry, circuit breaker, bulkhead e rate limiter, configuráveis via application.yml (dependência io.github.resilience4j:resilience4j-spring-boot3). (Visão de comunicação entre serviços em Microsserviços com Spring.)

Padrão O que faz Anotação
Timeout Limita o tempo de espera de uma chamada externa; evita bloqueio indefinido; permite falha rápida @TimeLimiter
Retry Tenta novamente em falhas temporárias (rede, serviços externos), com número de tentativas, intervalo e estratégia de backoff @Retry
Circuit Breaker Monitora falhas e abre o circuito ao atingir o limite; evita chamadas desnecessárias; permite recuperação gradual (half-open) @CircuitBreaker
Fallback Resposta alternativa quando ocorre a falha (valor padrão, cache ou resposta simplificada); mantém a experiência e evita propagar a falha fallbackMethod
Bulkhead Isola recursos (pools de threads ou semáforos) para que um serviço lento não consuma todos os recursos e uma falha não derrube a aplicação toda @Bulkhead
@CircuitBreaker(name = "estoque", fallbackMethod = "estoqueFallback")
public Estoque buscarEstoque(String sku) {
    return estoqueClient.buscar(sku);
}

public Estoque estoqueFallback(String sku, Throwable t) {
    return Estoque.indisponivel();
}

Versionamento de API

Evolua a API sem quebrar os clientes.

Estratégia Como Observação
Na URL /api/v1/usuarios, /api/v2/usuarios Simples e muito usada; facilita roteamento e manutenção; permite manter várias versões em paralelo
No header API-Version: 1 Mantém a URL limpa; útil em APIs públicas com vários clientes; combinável com outras estratégias
@RestController
@RequestMapping("/api/v1/usuarios")
public class UsuarioControllerV1 { /* ... */ }
  • Compatibilidade: evite mudanças que quebrem clientes existentes; adicione campos em vez de remover; siga princípios de design de APIs evolutivas.
  • Migração: comunique mudanças com antecedência, mantenha a versão antiga por um período, ofereça plano de migração e monitore o uso das versões para definir a descontinuação (ex.: header Warning avisando que a v1 será descontinuada em uma data).
  • Documentação: documente todas as versões e as diferenças entre elas (Swagger/OpenAPI), com exemplos de requisição e resposta por versão.

Validação avançada

Aprofunda a validação de dados com o Jakarta Bean Validation.

Recurso Uso
Mensagens Personalize com o atributo message ou o arquivo ValidationMessages.properties; facilita internacionalização (i18n) e mensagens amigáveis (@NotBlank(message = "O nome é obrigatório"))
Grupos Divida as validações por contexto (criação x atualização) com interfaces-marcador: @NotBlank(groups = Criacao.class); evita validações desnecessárias em cada cenário
Validação customizada Crie anotações próprias com @Constraint(validatedBy = ...) e implemente ConstraintValidator; para regras de domínio que as padrão não cobrem (ex.: @MaiorDeIdade)
@Valid em cascata Em parâmetros de controller (@Valid @RequestBody) e em objetos aninhados dentro de DTOs; falhas lançam MethodArgumentNotValidException, tratável no @RestControllerAdvice
@Constraint(validatedBy = MaiorDeIdadeValidator.class)
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MaiorDeIdade {
    String message() default "Deve ser maior de idade";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

Testes de integração

Mais confiança com cenários reais: testa o fluxo completo (controller → service → repository → banco) e ajuda a achar problemas de configuração e de integração entre camadas. (Complementa Testes no Spring Boot.)

Recurso Função
@SpringBootTest Carrega o contexto completo, com as configurações reais (beans, banco…); pode combinar com @AutoConfigureMockMvc
Banco de teste Banco isolado para os testes, como o H2 em memória; configure em application-test.properties (spring.datasource.url=jdbc:h2:mem:testdb, spring.jpa.hibernate.ddl-auto=create-drop); evita afetar dados de produção
MockMvc Testa os endpoints HTTP simulando requisições, sem subir servidor real; valida status, corpo e headers
Rollback @Transactional no teste desfaz os dados inseridos ao final, mantendo o banco limpo e permitindo repetir os testes
@SpringBootTest
@AutoConfigureMockMvc
@Transactional
class UsuarioIntegrationTest {
    @Autowired private MockMvc mockMvc;

    @Test
    void deveBuscarUsuario() throws Exception {
        mockMvc.perform(get("/usuarios/{id}", 1))
               .andExpect(status().isOk())
               .andExpect(jsonPath("$.nome").value("João"));
    }
}

Testcontainers

Definição: Testcontainers

Biblioteca que usa o Docker para criar contêineres reais (PostgreSQL, MySQL, Redis, Kafka…) durante os testes, gerenciando o ciclo de vida automaticamente (sobe antes, remove depois). Integra com JUnit 5 e Spring Boot Test.

  • Ambiente próximo da produção: evita mocks excessivos de infraestrutura e detecta problemas reais de configuração e compatibilidade (inclusive testando migrations e queries).
  • Banco isolado: cada execução tem um ambiente limpo e independente, sem conflito entre testes.
  • Confiável: resultados consistentes e reprodutíveis, reduzindo falhas por diferenças de ambiente.
@Testcontainers
@SpringBootTest
class ProdutoServiceTest {
    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15");
}

Eventos com Spring (arquitetura orientada a eventos)

Comunicação assíncrona, escalável e desacoplada entre componentes (versão em processo; para mensageria externa ver Mensageria).

Elemento Papel
Evento Algo que aconteceu no sistema, normalmente imutável (DTO ou record); pode ser de domínio ou de integração
Produtor Detecta uma ação de negócio e publica o evento (síncrona ou assincronamente); no Spring, via ApplicationEventPublisher
Consumidor/assinante Processa o evento publicado (@EventListener ou mensageria externa); pode atualizar caches, enviar e-mails, integrar sistemas; vários assinantes podem reagir ao mesmo evento em paralelo
Desacoplamento O produtor não conhece os consumidores (e vice-versa); a comunicação é baseada em eventos, o que facilita evolução, escalabilidade e resiliência
public record UsuarioCriadoEvent(Long id, String nome, String email) {}

@Service
public class UsuarioService {
    private final ApplicationEventPublisher publisher;
    // ... construtor ...
    public void criarUsuario(Usuario usuario) {
        usuarioRepository.save(usuario);
        publisher.publishEvent(new UsuarioCriadoEvent(usuario.getId(), usuario.getNome(), usuario.getEmail()));
    }
}

@Component
public class EnvioEmailListener {
    @EventListener
    public void handle(UsuarioCriadoEvent evento) {
        emailService.enviarBoasVindas(evento.email());
    }
}

Fluxo: ação (criar usuário) → evento publicado com os dados → consumidores processam. Novas funcionalidades entram sem alterar o produtor.

Tracing e métricas (observabilidade)

Combine traces, métricas e logs para uma visão completa e achar rapidamente a causa raiz. (Os três pilares na teoria: SRE.)

Conceito Detalhe
Trace Jornada completa de uma requisição distribuída; composto por vários spans; permite rastrear a requisição entre serviços
Span Unidade de trabalho dentro de um trace (nome, início/fim, tags, eventos); mostra onde o tempo é gasto e ajuda a achar gargalos
Correlação Usa o traceId para correlacionar logs, métricas e traces; pode ser incluído automaticamente nos logs (MDC)
Métricas Dados numéricos (latência, contadores, taxas) com Actuator e Micrometer; expostas ao Prometheus
Diagnóstico Ferramentas: Actuator, Prometheus, Grafana e OpenTelemetry
@RestController
public class PedidoController {
    private final Counter pedidos;

    public PedidoController(MeterRegistry registry) {
        this.pedidos = registry.counter("pedidos.total");
    }
}

String traceId = MDC.get("traceId");
log.info("Processando pedido - traceId: {}", traceId);

Traces para entender o fluxo, métricas para medir desempenho e logs para os detalhes: juntos formam a visão completa da aplicação.

OAuth2 com Spring

Autorização segura para aplicações e APIs (teoria dos papéis e grant types em Segurança).

Papel No Spring Boot
Cliente Aplicação (web, mobile, SPA ou back-end) que solicita acesso a recursos protegidos; possui client_id e client_secret; pede tokens ao servidor de autorização e usa o access token nas requisições (spring.security.oauth2.client.registration...)
Authorization Server Autentica o usuário e emite tokens (access e refresh); valida cliente e permissões; pode ser o Spring Authorization Server ou um provedor como Keycloak; implementa os fluxos (Authorization Code, Client Credentials…)
Access Token Token de curta duração que representa a autorização do cliente; normalmente um JWT; enviado em Authorization: Bearer <token>
Escopos Definem o que o token pode acessar (permissões), com controle fino; solicitados pelo cliente na autorização (scope=produtos:read produtos:write) e incluídos no access token
Recursos protegidos APIs que exigem access token válido; validam assinatura, expiração e escopos a cada requisição; no Spring Boot, protegidas com Spring Security
@RestController
@RequestMapping("/api/produtos")
@PreAuthorize("hasAuthority('SCOPE_produtos:read')")
public class ProdutoController { /* endpoint protegido */ }

Integração com APIs externas (RestClient)

O RestClient é o cliente HTTP moderno do Spring para consumir APIs (API fluente; suporta GET, POST, PUT, DELETE…); substitui o RestTemplate e é a abordagem recomendada.

RestClient restClient = RestClient.builder()
        .baseUrl("https://api.exemplo.com")
        .defaultHeader("Authorization", "Bearer TOKEN")
        .defaultHeader("Content-Type", "application/json")
        .build();

ClienteDTO cliente = restClient.get()
        .uri("/clientes/{id}", id)
        .retrieve()
        .body(ClienteDTO.class);
Aspecto Detalhe
Timeout Tempo máximo de conexão e leitura (no request factory), para as requisições não ficarem presas; torna a aplicação mais resiliente
Headers Authorization, Content-Type, Accept…; globais (defaultHeader) ou por requisição
Tratamento de erro Erros HTTP 4xx e 5xx; onStatus mapeia erros específicos e permite lançar exceções customizadas, facilitando mensagens claras
Resposta Converte o JSON diretamente em objetos Java (DTOs), listas ou respostas genéricas (ResponseEntity)
String resposta = restClient.get()
        .uri("/clientes/{id}", id)
        .retrieve()
        .onStatus(HttpStatusCode::isError, (req, res) -> {
            throw new RuntimeException("Erro na API: " + res.getStatusCode());
        })
        .body(String.class);

Combine com Resilience4j (timeout, retry, circuit breaker) para integrações externas confiáveis.

Filas avançadas: RabbitMQ e Kafka

Aprofunda a mensageria. Teoria de Kafka e EDA em Event-Driven Architecture.

RabbitMQ Kafka
Natureza Broker de mensagens baseado em filas e exchanges Plataforma de streaming distribuída, de alta escala
Armazenamento Filas duráveis, com TTL, DLQ e retries Logs particionados e imutáveis; alto throughput e tolerância a falhas
Integração Spring spring-boot-starter-amqp spring-kafka
Indicado para Comunicação assíncrona entre microsserviços Processamento de eventos em tempo real
// RabbitMQ: fila durável
@Bean
public Queue filaPedidos() {
    return QueueBuilder.durable("fila.pedidos").build();
}

// Kafka: tópico com partições e réplicas
@Bean
public NewTopic topicoPedidos() {
    return TopicBuilder.name("pedidos").partitions(6).replicas(3).build();
}

Partições (Kafka). Os tópicos são divididos em partições para paralelismo e escalabilidade. Cada partição mantém a ordem das mensagens; elas são distribuídas por chave (key) ou em round-robin; mais partições → maior throughput e processamento paralelo.

Consumidores. Leem as mensagens e processam de forma assíncrona; organizam-se em grupos (consumer groups): o Kafka distribui as partições entre os consumidores do grupo, permitindo escalabilidade horizontal e tolerância a falhas.

Confirmação (ack). Controla quando a mensagem é considerada processada. No Kafka, o offset pode ser confirmado automática ou manualmente — a confirmação manual aumenta a segurança e evita perda de dados; estratégias de retry e DLQ ajudam a tratar falhas.

@KafkaListener(topics = "pedidos", groupId = "grupo-pedidos")
public void consumir(PedidoEvent evento, Acknowledgment ack) {
    try {
        processar(evento);
        ack.acknowledge();                 // confirma o offset só após processar
    } catch (Exception e) {
        log.error("Erro ao processar: {}", e.getMessage());
    }
}

Auditoria

Rastreia quem fez o quê e quando. O Spring Data JPA preenche os campos de auditoria automaticamente ao persistir, quando a auditoria está habilitada (@EnableJpaAuditing mais @EntityListeners(AuditingEntityListener.class)).

Campo Anotação Conteúdo
createdBy @CreatedBy Quem criou o registro (nome, e-mail ou ID); depende de uma implementação de AuditorAware
createdDate @CreatedDate Data/hora de criação, preenchida na persistência
updatedBy @LastModifiedBy Quem fez a última atualização; atualizado a cada alteração; depende de AuditorAware
updatedDate @LastModifiedDate Data/hora da última atualização, atualizada a cada alteração
Histórico — Rastreia o histórico completo de alterações (versões anteriores dos registros), p. ex. com Hibernate Envers; útil para auditoria, rastreabilidade e conformidade (compliance)
@CreatedBy        private String createdBy;
@CreatedDate      private LocalDateTime createdDate;
@LastModifiedBy   private String updatedBy;
@LastModifiedDate private LocalDateTime updatedDate;

Internacionalização (i18n)

Suporta múltiplos idiomas de forma simples.

Elemento Papel
Locale Configuração regional e de idioma (idioma, país, variantes: pt-BR, en-US); resolvido automaticamente da requisição HTTP e personalizável (LocaleContextHolder.getLocale())
Mensagens Textos da aplicação externalizados em arquivos .properties, acessados pelo MessageSource; com chaves, parâmetros dinâmicos e formatação MessageFormat
Português messages.properties (padrão/fallback) ou messages_pt_BR.properties
Inglês messages_en.properties
MessageSource Componente que resolve as mensagens conforme o Locale (ex.: ResourceBundleMessageSource)
# messages.properties
usuario.nao.encontrado=Usuário não encontrado
pedido.sucesso=Pedido realizado com sucesso

# messages_en.properties
usuario.nao.encontrado=User not found
pedido.sucesso=Order placed successfully
String mensagem = messageSource.getMessage("pedido.sucesso", null, locale);

As chaves (em vez de textos no código) facilitam manutenção e evolução das traduções. Combina bem com validação avançada (mensagens em ValidationMessages.properties).

GraphQL

Definição: GraphQL

Linguagem de consulta para APIs em que o cliente decide quais campos quer receber, evitando overfetching (dados demais) e underfetching (dados de menos). Complementa ou substitui REST em cenários com muitos clientes (web, mobile). (Comparação com REST/RPC em Backend.)

Elemento Papel
Schema Define a estrutura dos dados em SDL (Schema Definition Language, arquivos .graphql): types, queries, mutations e relacionamentos; é o contrato entre cliente e servidor
Query Consulta dados de forma específica, pedindo só os campos necessários; suporta filtros, paginação e parâmetros; retorna JSON
Mutation Cria, atualiza ou remove dados (altera o estado no servidor); recebe argumentos e devolve o resultado da operação
Resolver Componente que busca e prepara os dados; conecta as operações do schema a serviços, repositórios e APIs; no Spring: @QueryMapping
Flexibilidade O cliente escolhe os campos; permite evoluir a API sem quebrar clientes; atende vários clientes
type Produto { id: ID!  nome: String!  preco: Float! }

query { produtos { id nome preco } }

mutation { criarProduto(nome: "Teclado", preco: 199.90) { id nome } }
@QueryMapping
public List<Produto> produtos() {
    return produtoService.buscarTodos();
}

gRPC

Definição: gRPC e Protocol Buffers

gRPC é um framework de RPC de alta performance, que usa HTTP/2 (multiplexação) e Protocol Buffers (protobuf) — formato binário, compacto e mais eficiente que JSON. É muito usado na comunicação interna entre microsserviços.

  • Contrato: definido em arquivos .proto (serviços, mensagens e métodos); gera classes e stubs para servidor e cliente, garantindo compatibilidade entre as partes.
  • Performance: menor latência e menor consumo de banda (no exemplo do mapa, a mesma mensagem ocupa ~37 bytes em JSON e ~13 em protobuf).
  • Streaming: quatro tipos — unary (uma requisição, uma resposta), server streaming (uma requisição, várias respostas), client streaming (várias requisições, uma resposta) e bidirectional (várias, várias).
  • Segurança: comunicação segura com TLS e autenticação (ex.: mTLS).
  • Integração Spring Boot via spring-boot-starter-grpc (porta de servidor configurável, p. ex. 9090).
message Produto {
  string id = 1;
  string nome = 2;
  double preco = 3;
}

service ProdutoService {
  rpc ListarProdutos(ListaRequest) returns (ListaResponse);
  rpc AcompanharEstoque(EstoqueRequest) returns (stream EstoqueResponse);
}

Migrações de banco (Flyway)

Complementa a conexão com banco: versiona e evolui o esquema de forma automática e confiável.

  • O Flyway executa scripts SQL automaticamente na inicialização e mantém o controle de versões e o histórico; funciona com vários bancos (PostgreSQL, MySQL, H2, Oracle).
  • Scripts: arquivos SQL em src/main/resources/db/migration, com DDL e DML, executados na ordem das versões.
  • Versões: nome no padrão V<versão>__<descrição>.sql (dois underscores); cada versão é executada uma única vez; garante evolução incremental e rastreável e evita alterações manuais em produção.
  • Histórico: a tabela flyway_schema_history registra versões, data, tempo de execução e status (SELECT version, description, success, installed_on FROM flyway_schema_history;).
  • Rollback: o Flyway (edição gratuita) não faz rollback automático; planeje-o com scripts específicos de undo (ex.: U1__desfazer_alteracao.sql) e teste migrações e rollback em homologação.
-- src/main/resources/db/migration/V1__criar_tabela.sql
CREATE TABLE usuario (
    id BIGINT PRIMARY KEY,
    nome VARCHAR(100) NOT NULL
);

Feature flags

Definição: Feature flag (feature toggle)

Chave de configuração que liga ou desliga uma funcionalidade em tempo de execução, sem novo deploy. O código fica pronto, mas inativo até a flag ser ativada.

Uso Detalhe
Ativar Por propriedade/configuração (feature.enabled=true), sem redeploy; pode variar por ambiente (dev, homologação, prod); permite ativação gradual, testes e validações
Desativar Desliga rápido em caso de problema (feature.enabled=false); rollback sem redeploy; pode ser controlado por configuração externa (ex.: Spring Cloud Config)
Rollout gradual Libera para um grupo de usuários (por percentual ou critérios como região/perfil: feature.new-ui.rollout=25); reduz riscos em produção
Experimento Testes A/B e validação de hipóteses; mede o impacto no negócio; integra com ferramentas de analytics
Segurança Protege funcionalidades sensíveis, libera só a usuários autorizados (combinável com roles), evita expor APIs/telas em produção e permite desativar rápido em incidentes
@Value("${feature.new-ui.enabled:false}")
private boolean novaUiAtiva;

Arquitetura hexagonal com Spring

Teoria em Padrões Arquiteturais. Isola o domínio, permitindo que a aplicação evolua independentemente de tecnologias.

Elemento Papel
Domínio Regras de negócio, entidades, value objects; independente de frameworks e tecnologias; o coração da aplicação
Portas Interfaces que definem os contratos entre o domínio e o mundo externo; de entrada (uso do sistema) e de saída (acesso a recursos externos); mantêm o domínio isolado
Adaptadores Implementam as portas; de entrada (controllers, consumidores de fila) e de saída (repositórios, APIs externas); convertem dados entre formatos
Aplicação Casos de uso; orquestra o fluxo entre portas de entrada, domínio e portas de saída; sem lógica de infraestrutura
Infraestrutura Implementações técnicas (banco, APIs, mensageria) com Spring Boot, JPA, Web…; substituível sem afetar domínio e aplicação

Fluxo: Entrada (requisição externa: HTTP, fila, CLI) → Caso de uso (aplica as regras) → Saída (banco, API, fila).

public interface PedidoRepository {                       // porta de saída (no domínio)
    Optional<Pedido> buscarPorId(Long id);
}

@Service
public class CriarPedidoUseCase {                         // aplicação
    private final PedidoRepository pedidoRepository;
    public Pedido executar(CriarPedidoCommand cmd) { /* ... */ return pedidoRepository.salvar(pedido); }
}

@Repository
public class PedidoJpaRepository implements PedidoRepository { /* Spring Data JPA */ }  // adaptador

API Gateway (Spring Cloud Gateway)

Entrada única para os serviços, centralizando roteamento, segurança, limites e monitoramento. Fluxo: cliente → gateway (aplica políticas e direciona) → serviço.

Função Detalhe
Entrada única Ponto único de acesso; centraliza requisições para vários serviços; simplifica a URL; desacopla o cliente da estrutura interna; permite políticas globais (segurança, limite, logs)
Roteamento Direciona ao serviço correto por paths, hosts, headers ou parâmetros; reescrita de rotas; balanceamento de carga entre instâncias; facilita evoluir os serviços sem impactar o cliente
Autenticação Valida a identidade antes de encaminhar (JWT, OAuth2/OpenID Connect; Keycloak, Auth0); bloqueia acesso não autorizado; propaga informações de autenticação (ex.: claims) aos serviços internos
Rate limit Limita o número de requisições por cliente (IP, usuário, chave de API); protege contra abuso; algoritmos como Token Bucket (ex.: RequestRateLimiter com Redis: replenishRate, burstCapacity)
Observabilidade Logs de entrada e saída, métricas (latência, taxa de erro), rastreamento distribuído (Trace/Correlation ID); integra com Prometheus, Grafana e Zipkin
spring:
  cloud:
    gateway:
      routes:
        - id: usuarios
          uri: http://usuarios-service
          predicates:
            - Path=/usuarios/**

Descoberta de serviços

Permite que os serviços se encontrem dinamicamente, sem endereços fixos (IP/porta). Fluxo: serviço se registra → cliente consulta pelo nome do serviço → recebe a lista de instâncias disponíveis. Ferramentas: Eureka, Consul.

Elemento Detalhe
Registro Os serviços se registram automaticamente no servidor de descoberta, informando nome, IP, porta e metadados; o registro é renovado periodicamente (heartbeat); instâncias são adicionadas/removidas dinamicamente
Localização O cliente consulta o servidor pelo nome lógico (service id) e recebe as instâncias; permite chamadas dinâmicas sem endereço fixo
Health check Verifica se as instâncias estão saudáveis (/actuator/health); remove automaticamente as indisponíveis do registro, evitando requisições a serviços fora do ar
Balanceamento Distribui as requisições entre as instâncias (do lado do cliente, client-side load balancer), com algoritmos como Round Robin; melhora uso de recursos, escalabilidade e tolerância a falhas
Instâncias Várias instâncias do mesmo serviço; se registram e se renovam; novas são detectadas em tempo real (escalabilidade horizontal); quando uma sai, é removida após o timeout de heartbeat
spring:
  application:
    name: pedido-service
  cloud:
    discovery:
      enabled: true
@Bean
@LoadBalanced
public WebClient.Builder webClientBuilder() { return WebClient.builder(); }

Com @LoadBalanced, o cliente chama http://pedido-service/... e o balanceador escolhe uma instância.

Configuração distribuída (Spring Cloud Config)

Gerencia configurações de forma centralizada e externa às aplicações.

Aspecto Detalhe
Config Server Servidor central de configuração para várias aplicações (Spring Cloud Config); fornece arquivos por aplicação, perfil e branch do Git; as aplicações buscam suas configurações na inicialização; fontes: repositório Git, sistema de arquivos etc.
Centralização Todas as configurações em um único local: facilita gestão e manutenção, garante consistência entre serviços, evita duplicação e permite versionamento e auditoria (Git)
Ambientes Configurações por perfil (meu-servico-dev.yml, -homolog.yml, -prod.yml), organizadas por aplicação e ambiente; podem usar branches por ambiente; facilita promover configurações entre ambientes
Atualização Atualiza configurações sem redeploy; mudanças no repositório refletem nas aplicações; propagação via Spring Cloud Bus; refresh em tempo de execução (POST /actuator/refresh)
Segurança Protege o acesso ao Config Server (Basic, OAuth2…); suporta criptografia de valores sensíveis; permissões por aplicação e perfil; integra com Spring Security ou Vault
# Config Server
spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/meu-org/configs

# Cliente (importa as configurações do servidor na inicialização)
spring:
  config:
    import: optional:configserver:http://localhost:8888

Transações distribuídas: Saga

Em microsserviços não há @Transactional entre serviços: cada um tem seu banco, e a consistência é eventual (não usa transações ACID tradicionais entre serviços), baseada em coordenação e eventos.

Definição: Saga

Padrão para gerenciar transações distribuídas dividindo a operação em passos locais: cada serviço confirma a sua etapa; se alguma falhar, executam-se compensações das etapas já concluídas. Pode ser orquestrada (um coordenador comanda os passos) ou coreografada (cada serviço reage a eventos).

Elemento Detalhe
Eventos Serviços publicam eventos ao concluir uma operação local; outros reagem; desacopla os serviços; Kafka, RabbitMQ ou Spring Events; comunicação assíncrona e escalável
Compensação Ação inversa que desfaz uma operação anterior (ex.: liberar estoque, cancelar pedido); cada serviço define a sua; deve ser idempotente (pode rodar mais de uma vez)
Falhas parciais Um serviço pode falhar enquanto outros concluem (timeouts, indisponibilidade, erros de rede); a Saga identifica e aciona as compensações; o sistema deve ser resiliente (retry, circuit breaker) e ter logs e monitoramento

Fluxo: Ação (criar pedido) → Evento (pedido confirmado) → Compensação em caso de falha (cancelar pedido).

@Service
public class PedidoService {
    private final ApplicationEventPublisher publisher;

    public void confirmarPedido(Long id) {
        publisher.publishEvent(new PedidoConfirmadoEvent(id));
    }
}

Idempotência

Definição: Idempotência

Propriedade de uma operação que pode ser repetida várias vezes sem produzir efeitos colaterais duplicados: o resultado da primeira execução é o que vale. Essencial em reenvios automáticos após falha de rede e em integrações com sistemas externos.

  • Mesma resposta: requisições repetidas devolvem o mesmo status e dados da operação original (ex.: {"id": 123, "status": "PROCESSADO"}), evitando registros duplicados.
  • Chave idempotente (Idempotency-Key): identificador único por operação e por cliente, enviado no cabeçalho HTTP (ou no corpo); permite localizar requisições anteriores no banco e evitar processamento duplicado.
  • Pagamentos: crucial em operações financeiras — impede cobranças duplicadas e garante que o débito ocorra uma só vez, mesmo com reenvio por falha de rede ou timeout.
  • Segurança: previne fraudes e ações não intencionais repetidas; permite auditoria e rastreabilidade; reduz riscos em integrações externas.
@PostMapping("/pedidos")
public ResponseEntity<Pedido> criarPedido(
        @RequestHeader("Idempotency-Key") String chave,
        @RequestBody PedidoRequest request) {
    // se a chave já foi processada, devolve o resultado original
}

Fluxo: requisição com a chave → verifica se já foi processada → devolve o mesmo resultado. (Idempotência dos verbos HTTP na teoria: Backend; também em EDA.)

Rate limiting

Controla o número de requisições para proteger a aplicação e garantir uso justo. (No gateway: API Gateway.)

Aspecto Detalhe
Limite por usuário Limite por usuário/cliente, identificado por ID, token ou IP; evita que um único usuário consuma todos os recursos
Janela de tempo Limita as requisições dentro de um intervalo (segundos, minutos, horas); após o limite, as novas são bloqueadas até a próxima janela; algoritmos Token Bucket ou Fixed Window
Proteção Previne DDoS e força bruta, sobrecarga nos serviços e no banco; limites globais e específicos; combina com autenticação, filtros e monitoramento
API pública Essencial em APIs expostas na internet; limites por chave de API ou IP; garante qualidade de serviço a todos e evita custos inesperados
429 Too Many Requests Status que indica que o limite foi excedido; pode incluir o cabeçalho Retry-After com o tempo de espera; melhora a comunicação com o cliente
return ResponseEntity.status(429)
        .header("Retry-After", "60")
        .body("Muitas requisições. Tente novamente mais tarde.");

Fluxo: identifica o usuário → consulta o limite na janela → permite ou devolve 429. (Em Java costuma-se usar bibliotecas como Bucket4j ou Resilience4j RateLimiter.)

Webhooks

Definição: Webhook

Mecanismo em que um sistema externo notifica a sua aplicação, por uma requisição HTTP (normalmente POST), quando um evento ocorre (pagamento aprovado, pedido atualizado) — de forma automática e em tempo real, evitando consultas constantes (polling).

Elemento Detalhe
Evento externo Acontecimento no sistema externo que dispara a chamada; integra sistemas de forma automática
Endpoint receptor Endpoint da sua aplicação que recebe o webhook; POST; público e acessível pela internet; processa os dados de forma segura e idempotente; valida origem e conteúdo
Assinatura (HMAC) Garante a autenticidade e que o payload não foi alterado no caminho; a chave secreta é compartilhada entre os sistemas; recalcula-se o HMAC do corpo e compara-se com o cabeçalho (ex.: X-Signature); rejeite requisições com assinatura inválida
Confirmação Responda HTTP 2xx quando processado; em erro, um código apropriado (4xx/5xx); processamentos longos devem ser assíncronos (ex.: fila) com resposta 200 imediata; registre os eventos para auditoria
Retry O emissor pode reenviar em caso de falha — por isso a aplicação deve ser idempotente; 5xx → o emissor tenta de novo; 2xx → sucesso; defina estratégia de retry com limite

Fluxo: evento externo → POST no endpoint → valida a assinatura → processa → devolve 200 OK. Mais sobre integração assíncrona e webhooks em EDA.

Processamento em lote (Spring Batch)

Framework do ecossistema Spring para processamento em lote de grandes volumes de dados, com reprocessamento, recuperação de falhas e rastreabilidade; indicado para cargas, extrações, migrações e processamento massivo (spring-boot-starter-batch).

Elemento Papel
Job Um processo de lote completo, composto por um ou mais steps; controla o fluxo de execução; aceita parâmetros; armazena metadados de cada execução (JobExecution); pode ser reiniciado em caso de falha
Step Uma etapa do processamento: leitura, processamento e escrita dos dados; baseado em chunks ou em tarefa simples (Tasklet); tem transações e controle de falhas; pode ser encadeado com outros steps
Chunk Modelo mais comum: divide o processamento em blocos; para cada bloco lê itens (ItemReader), processa (ItemProcessor) e escreve em lote (ItemWriter); melhora a performance e reduz o uso de memória; cada chunk é transacional — em falha, só o chunk é reprocessado
Relatório Informações sobre a execução (itens lidos, escritos, tempo, status, falhas) a partir dos metadados (JobExecution, StepExecution)
@Bean
public Step stepImportarClientes(StepBuilderFactory stepBuilderFactory,
                                 ItemReader<Cliente> reader,
                                 ItemProcessor<Cliente, Cliente> processor,
                                 ItemWriter<Cliente> writer) {
    return stepBuilderFactory.get("stepImportarClientes")
            .<Cliente, Cliente>chunk(100)
            .reader(reader).processor(processor).writer(writer)
            .build();
}

Fluxo: Job → Step → Writer. (Nas versões recentes do Spring Batch 5, usa-se StepBuilder com JobRepository e PlatformTransactionManager em vez de StepBuilderFactory, que foi descontinuado.)

AOT e Native Image

Gera um executável nativo da aplicação, com inicialização mais rápida e menor consumo de recursos.

Aspecto Detalhe
Compilação antecipada (AOT) Analisa a aplicação em tempo de build, gera código otimizado e reduz reflexão e proxies dinâmicos; produz um executável com apenas o necessário
GraalVM Ferramenta da Oracle que gera executáveis nativos por análise estática; suporta Java/Spring Boot; elimina a necessidade da JVM em produção; integra com o Spring AOT
Inicialização rápida Startup muito menor; ideal para ambientes serverless e contêineres; reduz o aquecimento da JVM (warmup); melhora o autoscaling
Memória menor Consome menos RAM e gera binário menor; eficiente em ambientes com recursos limitados e para reduzir custos
Limitações Nem todas as bibliotecas são compatíveis; reflexão, proxies e carregamento dinâmico têm restrições (exige hints de configuração, como @ImportRuntimeHints); build mais demorado; algumas funcionalidades da JVM não existem; exige testes cuidadosos antes de ir para produção
./mvnw -Pnative native:compile      # ou: ./gradlew nativeCompile

Fluxo: código-fonte → processamento AOT no build → nativeCompile (GraalVM) → executável nativo.

Programação reativa com Spring WebFlux

Conceitos de Mono, Flux e backpressure em Java Avançado.

Definição: Spring WebFlux

Stack web reativa e não bloqueante do Spring (sobre Netty por padrão), alternativa ao Spring MVC. Poucas threads (event loop) atendem muitas conexões simultâneas.

@RestController
@RequestMapping("/produtos")
public class ProdutoController {
    private final ProdutoRepository repo;                 // ReactiveCrudRepository (R2DBC/Mongo)

    @GetMapping            public Flux<Produto> listar()              { return repo.findAll(); }
    @GetMapping("/{id}")   public Mono<Produto> buscar(@PathVariable Long id) {
        return repo.findById(id)
                   .switchIfEmpty(Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND)));
    }
    @PostMapping           public Mono<Produto> criar(@RequestBody Produto p) { return repo.save(p); }
}
  • Estilo funcional: RouterFunction + HandlerFunction definem as rotas sem anotações.
  • WebClient: cliente HTTP reativo (substitui o RestTemplate): webClient.get().uri("/x").retrieve().bodyToMono(Resposta.class).timeout(Duration.ofSeconds(2)).
  • Streaming: produces = MediaType.TEXT_EVENT_STREAM_VALUE devolve um Flux como Server-Sent Events.
  • Acesso a dados reativo: R2DBC (SQL), Spring Data MongoDB/Redis reativos. JDBC e JPA são bloqueantes — não os use dentro de um pipeline reativo (bloqueia o event loop).
  • Quando usar: muitas conexões concorrentes, streaming, integração com muitos serviços lentos. Quando evitar: CRUD tradicional com JPA — Spring MVC com threads virtuais (Java 21) dá boa escalabilidade com código imperativo mais simples. Depurar código reativo é mais difícil (stack traces fragmentadas).
  • Testes: StepVerifier (Reactor Test) e WebTestClient.

WebSocket e STOMP

Definição: WebSocket

Protocolo de comunicação bidirecional e persistente sobre uma única conexão TCP (começa com um handshake HTTP Upgrade). Permite que o servidor envie dados ao cliente sem ser consultado — chat, notificações, painéis em tempo real. STOMP é um protocolo de mensagens simples que roda sobre o WebSocket (tópicos, filas, subscribe).

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    public void configureMessageBroker(MessageBrokerRegistry r) {
        r.enableSimpleBroker("/topic");                 // destinos de saída (broker em memória)
        r.setApplicationDestinationPrefixes("/app");    // destinos de entrada
    }
    public void registerStompEndpoints(StompEndpointRegistry r) {
        r.addEndpoint("/ws").setAllowedOrigins("https://app.exemplo.com").withSockJS();
    }
}

@Controller
public class ChatController {
    @MessageMapping("/chat")          // cliente envia para /app/chat
    @SendTo("/topic/mensagens")       // todos os inscritos recebem
    public Mensagem enviar(Mensagem m) { return m; }
}
  • Segurança: autentique no handshake (JWT na URL/cabeçalho), restrinja allowedOrigins e autorize destinos. Para vários servidores, use um broker externo (RabbitMQ/Redis) em vez do broker em memória.
  • Alternativas: Server-Sent Events (só servidor → cliente, mais simples) e polling.

Busca e análise com Elasticsearch

Definição: Elasticsearch

Mecanismo de busca e análise distribuído baseado em índice invertido: ótimo para busca textual (relevância, fuzzy, sinônimos), filtros e agregações em grandes volumes de dados e logs (stack ELK). Não substitui o banco relacional: use-o como índice de leitura, alimentado a partir da fonte da verdade (via eventos/CDC).

@Document(indexName = "produtos")
public class ProdutoDoc {
    @Id private String id;
    @Field(type = FieldType.Text, analyzer = "portuguese") private String nome;
    @Field(type = FieldType.Keyword) private String categoria;
}
public interface ProdutoSearchRepository extends ElasticsearchRepository<ProdutoDoc, String> {
    List<ProdutoDoc> findByNomeContaining(String termo);
}

Conceitos: índice, documento, mapeamento (Text analisado x Keyword exato), analisadores (tokenização, minúsculas, remoção de stop words, stemming), shards e réplicas. É um caso clássico de CQRS: o banco grava, o Elasticsearch serve as buscas, com consistência eventual.

Origem, componentes e rotina de desenvolvimento

Por que o Spring Boot existiu. Com o crescimento do Spring Framework vieram muitos módulos, dependências e configuração (XML, depois anotações). O Spring Boot (primeira versão em abril de 2014) nasceu para reduzir a configuração e para facilitar aplicações prontas para nuvem, apoiado na anotação @Conditional (Spring 4), que ativa configurações só se certas bibliotecas estão presentes. A mudança de modelo: antes a aplicação rodava dentro de um servidor de aplicação; agora o Spring Boot embute o servidor (Tomcat por padrão) e controla tudo, gerando um JAR executável.

Componentes do Spring Boot: Starters (conjuntos de dependências por finalidade: web, data-jpa, security...), Auto-configuration (configura os beans a partir do que há no classpath), Actuator (monitoramento), CLI (criar protótipos por linha de comando, spring init, equivalente ao Spring Initializr em start.spring.io) e Tools (devtools e IDEs: Spring Tools Suite, IntelliJ IDEA, VS Code).

Definição: versão LTS e baseline

LTS (Long Term Support) é a versão do Java com suporte estendido de correções (hoje, uma a cada dois anos: 17, 21...); em produção, prefira LTS. Baseline é a versão mínima exigida: o Spring Framework 6 / Spring Boot 3 exigem Java 17, e o código do framework foi reescrito para usar seus recursos.

Executar código na partida

As interfaces CommandLineRunner e ApplicationRunner executam um método run logo após o contexto subir (carga inicial de dados, verificações). A diferença: a primeira recebe os argumentos como String[]; a segunda, um ApplicationArguments (com opções nomeadas). Podem existir várias (ordene com @Order). Para logs, use o SLF4J (LoggerFactory.getLogger(...)) em vez de System.out.println; e a injeção por construtor dispensa o @Autowired quando há um único construtor.

Produtividade

  • DevTools: reinício automático rápido ao alterar classes, LiveReload do navegador e padrões de desenvolvimento (cache de templates desligado). É ignorado no empacotamento do JAR.
  • Docker e Docker Compose no desenvolvimento: subir banco, fila e cache em contêineres (spring-boot-docker-compose detecta e liga os serviços); a imagem da aplicação nasce de um Dockerfile simples sobre uma imagem com Java 17+ (veja Containers e Docker).
  • Personalização: banner de partida próprio (banner.txt), páginas de erro por código HTTP (templates/error/404.html, 500.html) e templates Thymeleaf com layouts e fragmentos reutilizáveis.

Empacotamento e execução

Forma Como Observações
JAR simples Só as classes da aplicação Precisa das dependências no classpath
JAR executável ("fat jar") mvn package com o spring-boot-maven-plugin; java -jar app.jar O padrão; inclui as dependências e o servidor embutido
Como serviço Em Linux, o JAR pode virar um serviço (systemd/init.d) com parâmetros da JVM em arquivo de configuração No Windows e macOS, use wrappers de terceiros (WinSW, Launchd)
WAR Estender SpringBootServletInitializer e implantar em um Tomcat, Jetty, WildFly já existente Para ambientes legados
Imagem de contêiner Dockerfile ou buildpacks (mvn spring-boot:build-image) Base do deploy em nuvem e Kubernetes
Imagem nativa GraalVM compila para código nativo (AOT e Native Image) Partida em milissegundos e menos memória; build mais lento

O contêiner web é substituível (Tomcat → Jetty ou Undertow trocando o starter), e as propriedades server.* (porta, contexto, SSL, compressão) valem para o escolhido. Para ambientes diferentes (desenvolvimento, homologação, nuvem) use perfis (application-prod.properties, --spring.profiles.active=prod) e variáveis de ambiente para usuários e senhas (Configuração na prática).

Microsserviços com Spring: estrutura de um exemplo

Um exemplo típico de loja com microsserviços: user-api, product-api e shopping-api (compras, que consulta os outros dois), cada um com sua camada Controller → Service → Repository e seu banco, comunicando-se por REST com DTOs compartilhados; exceções de negócio próprias (usuário/produto não encontrado) mapeadas para 404 com @ControllerAdvice; um api-gateway na frente; e Lombok (@Getter, @Builder, @RequiredArgsConstructor) para reduzir código repetitivo (use com cuidado em entidades JPA: @Data gera equals/hashCode problemáticos). A implantação em Kubernetes usa um Deployment por serviço, Services para expor, ConfigMaps para configuração e Secrets para credenciais, com o banco em outro Deployment (Kubernetes com Spring Boot).

Checklist de produção

Antes de publicar, confira:

Área Itens
Segurança HTTPS em produção; autenticação e autorização adequadas; proteger endpoints sensíveis; segredos em variáveis de ambiente ou gerenciador; dependências atualizadas; políticas de segurança (CORS, CSRF, rate limiting)
Logs Logs estruturados; nível adequado para produção; IDs de rastreabilidade; centralizar (ELK, Grafana Loki); não expor dados sensíveis; retenção apropriada
Métricas Expor métricas com Actuator; monitorar a saúde (/actuator/health); métricas de JVM, HTTP e negócio; integrar com Prometheus/Grafana; alertas para indicadores críticos; acompanhar CPU, memória e tempo de resposta
Testes Todos os testes automatizados; cobertura mínima (unidade e integração); testes de carga e desempenho; cenários de falha e recuperação; ambientes semelhantes à produção; automatizar no CI/CD
Backup Backup regular do banco, em local seguro e externo; testar a restauração periodicamente; política de retenção; incluir arquivos e configurações; plano de recuperação de desastres documentado e testado

Pronto para publicar quando: funcionalidades testadas, segurança configurada, logs e métricas habilitados, backup realizado, documentação atualizada, ambiente de produção validado, variáveis de ambiente configuradas, pipeline de deploy testado, monitoramento e alertas ativos e equipe alinhada. Detalhes de deploy em Deploy em nuvem.

Escalabilidade horizontal

Cresce adicionando mais instâncias, garantindo alta disponibilidade, melhor desempenho e resiliência.

Aspecto Detalhe
Múltiplas instâncias Várias instâncias em paralelo, todas idênticas (mesmo artefato), com o tráfego distribuído entre elas; mais disponibilidade e tolerância a falhas; em VMs, contêineres ou nuvem (Kubernetes, ECS)
Load balancer Distribui as requisições entre as instâncias; pode ser de nuvem (ALB), Nginx, HAProxy; faz health check para remover instâncias indisponíveis; algoritmos (round robin, least connections)
Stateless A aplicação não guarda estado em memória local: qualquer instância atende qualquer requisição; guarde dados em banco, cache externo ou serviços dedicados; evite variáveis estáticas e sessões locais
Sessão externa Para aplicações com sessão, armazene-a em repositório externo (Redis, banco) com Spring Session (spring.session.store-type=redis); evita perder sessão ao escalar ou reiniciar
Auto scaling Ajusta automaticamente o número de instâncias conforme a demanda (picos/queda), via métricas (CPU, memória, requisições); AWS Auto Scaling ou Kubernetes HPA
# Kubernetes - Horizontal Pod Autoscaler
spec:
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70

(Escalar vertical x horizontal no contexto de LLMs: ver I.A..)

Segurança de segredos

Prática Detalhe
Variáveis de ambiente Guarde segredos nelas, não em application.properties/yml (spring.datasource.password=${SPRING_DATASOURCE_PASSWORD}); funciona bem com Docker, Kubernetes e nuvem
Vault Use um gerenciador de segredos como o HashiCorp Vault: centraliza o armazenamento, controla o acesso por políticas e perfis, integra com Spring Cloud Vault e obtém segredos dinamicamente em tempo de execução
Secrets Armazene apenas o necessário (senhas, chaves de API, certificados, tokens), fora do código-fonte, com acesso restrito por função (menor privilégio) e auditoria de uso
Rotação Rotação periódica e automatizada; evite segredos de longa duração; use rotação automática do Vault/nuvem; garanta que a aplicação aceite a atualização sem downtime
Nunca versionar senhas Nunca faça commit de senhas, chaves ou tokens; use .gitignore (.env, secrets/, arquivos de configuração com segredos); revise pull requests; em caso de vazamento, rotacione imediatamente

Observabilidade completa

Entender o comportamento da aplicação em tempo real, de ponta a ponta, combinando os três sinais: logs (o que aconteceu), métricas (como está agora) e traces (por que aconteceu). Visão completa = diagnóstico mais rápido e aplicações mais confiáveis. (Fundamentos em SRE; introdução em Logs, Actuator e Tracing e métricas.)

Sinal Boas práticas
Logs Estruturados (JSON); níveis adequados; incluir contexto (correlationId, userId); SLF4J + Logback; evitar dados sensíveis (senhas, tokens, dados pessoais); centralizar (ELK, Grafana Loki, Cloud Logging)
Métricas Spring Actuator + Micrometer como abstração; métricas de JVM, HTTP e customizadas; integrar com Prometheus e Grafana; monitorar CPU, memória, threads, requisições, taxa de erro e latência; métricas de negócio (pedidos, usuários); tags para segmentação (endpoint, status)
Traces Spring Cloud Sleuth ou Micrometer Tracing; propagar o traceId entre serviços; integração com OpenTelemetry; visualizar no Jaeger, Zipkin ou Grafana Tempo; identificar gargalos e latências; correlacionar com logs e métricas
Alertas Para indicadores críticos, com regras no Prometheus + Alertmanager; saúde (/actuator/health); alertas de erro, latência, recursos e indisponibilidade; canais (e-mail, Slack, Teams, PagerDuty); reduzir falsos positivos; testar os alertas periodicamente
Dashboards No Grafana (métricas, logs e traces); acompanhar saúde, SLAs e SLOs; latência, taxa de erro, throughput e recursos; painéis técnicos e de negócio; variáveis e filtros; compartilhar com a equipe
log.info("Pedido processado | orderId={} | userId={}", orderId, userId);
# exemplo de regra de alerta (Prometheus): alta taxa de erros 5xx
- alert: HighErrorRate
  expr: rate(http_server_requests_seconds_count{status=~"5.."}[5m]) > 0.05
  for: 5m
  labels:
    severity: critical

Documentação e contratos de API

Documente, defina e evolua os contratos da API de forma clara e estável (complementa OpenAPI e Swagger).

  • OpenAPI: documente a API REST com OpenAPI/Swagger e integre via springdoc-openapi; gera documentação interativa (Swagger UI); inclua descrições, exemplos e códigos de resposta; mantenha-a sempre atualizada.
  • Contrato: defina claramente requisições, respostas e códigos HTTP; documente regras de negócio e validações; inclua os schemas de dados (DTOs); estabeleça exemplos reais; trate erros e códigos de resposta de forma padronizada.
  • Exemplos: requisição e resposta com cenários de sucesso e erro; exemplos realistas (curl, JSON, payloads completos); destaque campos obrigatórios e opcionais.
  • Consumidores: documentação para desenvolvedores, times e parceiros, em ambiente acessível, com guia de início rápido, exemplos de integração em várias linguagens, limites de uso e boas práticas, e canal de suporte.
  • Compatibilidade: versione (/v1); mantenha compatibilidade entre versões; evite breaking changes desnecessárias; documente mudanças em um changelog; use depreciação gradual (deprecated = true em @Operation); adote testes de contrato para garantir a compatibilidade.
@Operation(summary = "Obtém produto por ID", deprecated = true)
@GetMapping("/v1/produtos/{id}")
public ProdutoDTO obterProduto(@PathVariable Long id) { /* ... */ }
curl -X POST https://api.exemplo.com/produtos \
  -H "Content-Type: application/json" \
  -d '{"nome":"Notebook","preco":3499.90}'

Dependências e vulnerabilidades

Mantenha as dependências atualizadas, seguras e livres de vulnerabilidades.

Tema Boas práticas
Versões Use versões estáveis e suportadas, preferindo LTS; evite versões em fim de vida (EOL); defina versões explícitas; acompanhe o ciclo de vida; mantenha consistência entre módulos
CVE Monitore vulnerabilidades conhecidas (CVE, Common Vulnerabilities and Exposures); consulte bases oficiais (NVD, Snyk); avalie a severidade (CVSS); verifique se a vulnerabilidade afeta a sua aplicação; priorize críticas e de alta severidade
Dependências transitivas Dependências das suas dependências: visualize a árvore (./mvnw dependency:tree), identifique versões conflitantes, exclua as desnecessárias (<exclusions>), sobreponha versões quando necessário e monitore vulnerabilidades também nelas
Atualização Processo regular, com automação (Dependabot, Renovate); teste após cada atualização; leia as release notes; verifique mudanças incompatíveis; planeje janelas em ambientes controlados (./mvnw versions:display-dependency-updates)
Revisão Auditorias periódicas; análise de segurança (OWASP Dependency-Check, Snyk); relatórios de vulnerabilidades; política de aprovação de dependências; documente decisões; inclua a revisão no CI/CD (./mvnw org.owasp:dependency-check-maven:check)

Compatibilidade e migrações

Evolua o sistema mantendo a compatibilidade e minimizando impactos (complementa versionamento de API e Flyway).

Eixo Prática
Versões de API Versionamento explícito, de preferência na URL (/v1, /v2); compatibilidade entre versões; documentar mudanças (changelog); manter versões antigas ativas durante a transição; evitar breaking changes
Banco Avaliar o impacto no esquema; migrações versionadas e idempotentes (Flyway/Liquibase); manter compatibilidade de leitura/escrita entre versões; planejar rollback; testar em homologação (ex.: ALTER TABLE produto ADD COLUMN descricao TEXT;)
Clientes antigos Mapear quais clientes usam cada versão; manter endpoints legados temporariamente; documentação clara de migração; comunicar prazos de descontinuação; monitorar o uso de versões antigas; oferecer suporte na transição
Rollout Deploy gradual; feature flags; canary (ex.: 5% → 25% → 50% → 100%); monitorar métricas e erros em tempo real; plano de rollback rápido; validar a nova versão com usuários reais
Plano de migração Objetivos e escopo; levantar dependências e riscos; cronograma realista; execução em etapas com validações; documentar cada passo; concluir removendo componentes legados
@ConditionalOnProperty(name = "feature.nova-api", havingValue = "true")
@RestController
public class NovaApiController { /* nova funcionalidade */ }

Para mudar sem quebrar: manter compatibilidade retroativa, versionar APIs e esquema, usar migrações versionadas, testar em staging, comunicar mudanças, monitorar versões antigas, usar feature flags, fazer rollout gradual, validar métricas e logs e remover o legado no momento certo.

Estratégias de cache

Aprofunda o cache com decisões de arquitetura.

Estratégia Detalhe
Cache local Dados na memória da própria aplicação; ideal para dados pouco mutáveis e de acesso frequente; baixa latência e implementação simples; limitado à instância, não compartilhado entre instâncias
Redis Cache distribuído em memória; alta performance e escalabilidade; compartilha dados entre várias instâncias; suporta expiração (TTL), remoção e várias estruturas; integração simples com Spring Data Redis (spring.data.redis.host/port)
TTL Tempo de vida do item: após o TTL, o dado é removido automaticamente, evitando dados desatualizados; configurável por cache ou por item; equilibra performance e consistência
Invalidação Remove/atualiza dados quando há mudanças; evita informação desatualizada; manual ou automática com @CacheEvict e @CachePut; essencial em operações de escrita (criar, atualizar, excluir)
Consistência Equilíbrio entre performance e dados atualizados; escolha a estratégia de invalidação adequada; TTL alinhado ao negócio; use Redis e eventos de domínio em cenários distribuídos; monitore hits, misses e expiração
@Cacheable(value = "produtos", unless = "#result == null", sync = true)
public Produto buscarProduto(Long id) { return repository.findById(id).orElse(null); }

@CacheEvict(value = "usuarios", key = "#id")
public void excluir(Long id) { repository.deleteById(id); }

Padrões clássicos: Cache-Aside (o mais comum — 1) tenta ler do cache; 2) se não existir, busca no banco e armazena; 3) devolve o valor), Write-Through (escreve no cache e no banco juntos) e Write-Behind (escreve no cache e grava no banco de forma assíncrona).

Segurança em produção

Complementa Segurança de segredos.

Tema Boas práticas
HTTPS Obrigatório em produção; obtenha e renove certificados (ex.: Let's Encrypt); redirecione HTTP → HTTPS; habilite HSTS (HTTP Strict Transport Security); configure o proxy reverso (Nginx, ALB); evite conteúdo misto
Headers de segurança Configure cabeçalhos recomendados (CSP, HSTS, X-Frame-Options); protege contra clickjacking, XSS e MIME sniffing; remova cabeçalhos desnecessários; valide com ferramentas de auditoria (securityheaders.com)
CORS Configure explicitamente; restrinja as origens; permita só os métodos necessários; evite * em produção; controle os headers permitidos; defina o maxAge do cache
Secrets Nada no código; variáveis de ambiente; gerenciador de segredos (AWS Secrets Manager, Vault); proteja chaves, senhas e tokens; rotacione periodicamente; restrinja o acesso
Menor privilégio Conceda apenas o necessário; contas e papéis específicos; restrinja acesso a bancos e serviços; separe permissões por ambiente; revise periodicamente; monitore atividades suspeitas (ex.: usuário de banco só de leitura: CREATE USER app_readonly; GRANT SELECT ON tabela TO app_readonly;)
http.headers(headers -> headers
    .contentSecurityPolicy(csp -> csp.policyDirectives("default-src 'self'"))
    .frameOptions(frame -> frame.deny())
    .httpStrictTransportSecurity(Customizer.withDefaults()));
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of("https://app.seudominio.com"));
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
config.setAllowedHeaders(List.of("Authorization", "Content-Type"));
config.setMaxAge(3600L);

Manutenção e refatoração

Código sustentável, evolutivo e de qualidade (teoria em Boas Práticas: refatoração, SOLID, DRY, KISS).

Tema Prática
Código limpo Nomes descritivos, métodos pequenos e coesos, remover código comentado e morto, composição em vez de herança, SOLID, legibilidade
Duplicação Identifique trechos duplicados, extraia métodos/componentes reutilizáveis, centralize regras comuns, DRY, uma única fonte da verdade
Testes Testes automatizados e atualizados (unidade e integração), cobertura das regras críticas, rodar antes e depois das mudanças, mocks quando necessário, verificar que a refatoração não quebrou o comportamento, cenários de borda e de exceção
Pequenos passos Refatorações pequenas e incrementais; código funcionando a cada passo; commits frequentes e descritivos; branches para mudanças maiores; validar com testes após cada alteração; evitar mudanças muito grandes
Revisão Code review em equipe; avaliar legibilidade, estrutura e boas práticas; apontar melhorias; ferramentas como SonarQube; compartilhar conhecimento

Refatorar com segurança: testes automatizados cobrindo o comportamento, controle de versão (Git), pequenos passos, executar os testes a cada mudança, análise estática (SpotBugs, SonarQube), revisão de código e monitoramento após o deploy.

git checkout -b refactor/usuario-service
git commit -m "refactor: extrai método de validação"

Arquitetura de sistemas grandes

Organize o sistema em módulos bem definidos, com limites claros, dependências controladas e evolução contínua. Fluxo: domínio → módulos → serviços (identifique os domínios, organize em módulos coesos e exponha como serviços REST/gRPC/eventos).

Eixo Prática
Módulos Módulos coesos, cada um com uma responsabilidade bem definida (SRP); baixo acoplamento; prefira uma arquitetura modular monolítica ou microsserviços
Limites Limites claros de domínio e contexto; separação em camadas (API, aplicação, domínio, infraestrutura); evite vazamento de modelo entre módulos; DDD quando fizer sentido; contratos bem definidos entre módulos/serviços
Dependências Baixo acoplamento; dependa apenas de abstrações (interfaces); evite dependências circulares; injeção de dependência; comunicação assíncrona entre serviços quando aplicável; documente contratos de integração (REST, eventos)
Equipes Organize por domínio (squads: Pedidos, Clientes); ownership claro dos módulos; autonomia com alinhamento (arquitetura e padrões); convenções e guias; comunidades de prática
Evolução Projete para mudança; testes automatizados; versionamento de APIs e contratos; evolução incremental (Strangler Fig: substituir o legado aos poucos); monitorar o impacto; refatorar continuamente
com.exemplo.pedidos.api
com.exemplo.pedidos.aplicacao
com.exemplo.pedidos.dominio
com.exemplo.pedidos.infra

Teoria: DDD e Microsserviços.

Troubleshooting

Método estruturado: sintoma → diagnóstico → solução.

Etapa Como proceder
Logs Logs bem estruturados e significativos; contexto (id da requisição, usuário); evitar excesso em produção; níveis ERROR/WARN/INFO/DEBUG; SLF4J + Logback (ex.: logging.level.root=INFO, logging.level.com.exemplo=DEBUG)
Stack trace Leia de baixo para cima (a causa mais original primeiro); identifique a exceção principal (Caused by); analise a cadeia de chamadas; procure classes e métodos do seu projeto; diferencie erros de configuração, negócio e infraestrutura
Reprodução Reproduza de forma consistente; isole o cenário (ambiente, dados, requisições); use testes automatizados; simplifique ao mínimo; verifique se ocorre só em produção ou também local (docker compose up -d + curl)
Causa raiz Analise evidências (logs, stack trace, métricas, código); pergunte "por quê?" até chegar à causa; considere mudanças recentes (deploys, configurações, dependências); verifique causas comuns (timeouts, transações, concorrência, recursos); evite suposições — valide com dados
Correção Solução simples e segura; valide com testes (unidade e integração); faça deploy e monitore; documente o problema e a solução; considere ações preventivas

Causas raiz comuns: configuração incorreta, dados inválidos, dependência indisponível, problema de transação, condição de corrida (concorrência) e mudança recente no código ou na infraestrutura.

Caused by: java.lang.NullPointerException
    at com.exemplo.pedidos.repository.PedidoRepository.findById(...)
// leia a cadeia: a causa original está no "Caused by"

Arquitetura de referência

Uma arquitetura em camadas, clara e testável, seguindo as boas práticas do Spring Boot: API → Domínio → Persistência.

Camada Responsabilidade
Controller Recebe requisições HTTP; valida a entrada (DTO); converte para o modelo de domínio; delega a lógica ao Service; devolve o status e o DTO de saída; controllers leves (só orquestração)
Service Lógica de negócio; orquestra regras e transações (@Transactional); valida regras; usa o repository; mantém as regras isoladas de detalhes de infraestrutura
Repository Abstrai o acesso a dados; estende JpaRepository; CRUD automático; consultas derivadas pelo nome; @Repository para semântica clara; consultas complexas em métodos personalizados
Banco Dados persistentes em um SGBD (PostgreSQL, MySQL); conexão via application.yml; migrations (Flyway/Liquibase); modele esquema e índices; backups e monitoramento; em produção, ddl-auto: validate
Observabilidade SLF4J + Logback; métricas com Micrometer; Prometheus e Grafana; tracing distribuído (OpenTelemetry); saúde com Actuator; acompanhar logs, métricas e traces em produção
@RestController
@RequestMapping("/api/pedidos")
public class PedidoController {
    private final PedidoService pedidoService;

    @PostMapping
    public ResponseEntity<PedidoResponse> criar(@RequestBody @Valid PedidoRequest request) {
        var pedido = pedidoService.criar(request);
        return ResponseEntity.status(HttpStatus.CREATED).body(new PedidoResponse(pedido));
    }
}

@Service
@Transactional
public class PedidoService {
    private final PedidoRepository pedidoRepository;

    public Pedido criar(PedidoRequest request) {
        var pedido = new Pedido(request);
        return pedidoRepository.save(pedido);
    }
}

@Repository
public interface PedidoRepository extends JpaRepository<Pedido, Long> {
    List<Pedido> findByClienteId(Long clienteId);
    Optional<Pedido> findByNumero(String numero);
}

Checklist de segurança

Proteja a aplicação com boas práticas, reduzindo riscos e aumentando a resiliência. Princípio: negue por padrão e permita explicitamente; habilite segurança desde o início do projeto; aplique segurança em todas as camadas; valide entradas e trate erros de forma segura; monitore e audite continuamente.

Área Itens
Autenticação Spring Security; preferir OAuth2/OpenID Connect; senhas com hash forte (BCrypt); autenticação multifator (MFA); tokens JWT com expiração curta; recuperação de conta segura
Autorização Controle por papéis (RBAC); @PreAuthorize; menor privilégio; proteger endpoints sensíveis por perfil; validar permissões no backend (não confiar só no front-end); revisar permissões periodicamente
HTTPS Em todos os ambientes (inclusive homologação); certificados corretos; redirecionar HTTP → HTTPS; HSTS; TLS 1.2 ou superior; desabilitar protocolos e cifras inseguros
Secrets Nunca no código; variáveis de ambiente ou cofre (Vault, AWS Secrets Manager); rotação periódica; restringir acesso; não expor segredos em logs; perfis por ambiente
Dependências Mantê-las atualizadas; monitorar vulnerabilidades (Dependabot); remover as não utilizadas; evitar bibliotecas sem manutenção; verificar CVEs regularmente; versões estáveis e confiáveis

Checklist de deploy

Deploy seguro, confiável e rastreável. Fluxo: Build → Teste → Deploy → Monitoramento.

Etapa Itens
Build Maven/Gradle com build reprodutível; versão definida (sem snapshot); JAR com todas as dependências; plugin do Spring Boot; incluir informações de build (git, versão, data); armazenar o artefato em repositório (Nexus, Artifactory, GitHub Packages)
Testes Unitários e de integração; cobertura mínima; testes de contrato; smoke tests em homologação; validar dependências e configurações; só fazer deploy se os testes passarem
Variáveis Externalizar configurações; variáveis de ambiente em produção; nunca versionar segredos; gerenciador de segredos; validar as variáveis obrigatórias na inicialização; perfis (dev, hom, prod)
Migrações Versionamento do banco (Flyway/Liquibase); testar em homologação; migrações idempotentes; scripts versionados no repositório; plano de rollback das migrações
Rollback Plano definido; manter versões anteriores disponíveis; deploys versionados (tags ou imagens imutáveis); automatizar o rollback; documentar os passos de recuperação; testar o rollback periodicamente
./mvnw clean package -DskipTests        # empacota
docker run -d --name app -p 8080:8080 minha-app:1.0.0   # voltar à versão anterior = rodar a imagem anterior

Projeto completo: da ideia à produção

Integrando todas as partes do ecossistema: Ideia → Código → Produção.

Fase O que fazer
Requisitos Levantar e documentar requisitos funcionais (ex.: RF-001 "cadastro de clientes") e não funcionais (ex.: RNF-001 "responder em até 2 s"); personas e casos de uso; critérios de aceite; priorizar (MVP); manter a documentação atualizada (ver Requisitos)
Domínio Entidades claras, relacionamentos e regras de negócio; boas práticas de DDD quando fizer sentido; modelo coeso e simples; domínio isolado da infraestrutura
API Endpoints REST bem definidos; DTOs de entrada/saída; validações (Bean Validation); respostas padronizadas e tratamento de erros; documentação Swagger/OpenAPI
Banco Escolher o banco adequado (PostgreSQL, MySQL); acesso com Spring Data JPA; esquema com Flyway/Liquibase; índices e relacionamentos; boas práticas de performance
Testes Unitários para regras de negócio; testes de serviço e repositório; integração com @SpringBootTest; cobertura de cenários críticos; testes automatizados no pipeline
Deploy Empacotar o JAR com Maven/Gradle; Docker; implantar (VPS, nuvem); variáveis e segredos configurados; monitorar logs, métricas e health check
FROM eclipse-temurin:17-jre
WORKDIR /app
COPY target/projeto.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
docker build -t projeto .
docker run -p 8080:8080 projeto

Qualidade de código

Base de um sistema confiável, evolutivo e de fácil manutenção: simples, testável e sustentável. (Princípios em Boas Práticas.)

Tema Prática
SOLID S responsabilidade única; O aberto para extensão, fechado para modificação; L substituição de Liskov; I segregação de interfaces; D inversão de dependências (depender de abstrações)
Coesão Cada classe com uma responsabilidade; agrupar métodos relacionados; evitar classes com muitos métodos e responsabilidades; extrair classes quando o comportamento crescer; nomes de pacotes e classes refletindo o domínio
Acoplamento Baixo acoplamento entre classes e módulos; interfaces para diminuir dependências; injeção de dependências; evitar dependência de implementações concretas
Legibilidade Nomes claros; métodos pequenos e focados; formatação consistente; evitar números e strings mágicas; comentar o porquê, não o óbvio; "código que pareça uma história"
Revisão Code review regular; legibilidade, simplicidade e boas práticas; verificar testes e cobertura; feedback construtivo; análise estática (SonarQube)
// Alto acoplamento (evitar)
private final EnviadorEmail email = new EnviadorEmail();

// Baixo acoplamento (preferir)
private final Notificador notificador;
public PedidoService(Notificador notificador) { this.notificador = notificador; }

Estratégia de testes

Combine níveis de teste para qualidade, confiança e entrega contínua: rápidos → realistas → completos. (Teoria de testes em Qualidade.)

Nível Detalhe
Unitário Uma unidade isolada; mocks para dependências externas; rápidos e determinísticos; foco em regras de negócio e cenários; boa cobertura; JUnit 5 e Mockito (@ExtendWith(MockitoExtension.class), @Mock, @InjectMocks)
Integração Interação entre componentes; banco e dependências reais; valida o fluxo da camada/módulo; @SpringBootTest e @DataJpaTest (com @AutoConfigureTestDatabase); containers (Testcontainers); isolamento e limpeza dos dados
Contrato Define e valida o contrato das APIs; Consumer-Driven Contracts (Pact); garante compatibilidade entre serviços; detecta quebras cedo; verificação automatizada no pipeline
End-to-end O sistema completo, de ponta a ponta; simula o usuário real; fluxos críticos de negócio; Selenium ou Playwright (ou TestRestTemplate com webEnvironment = RANDOM_PORT); poucos cenários, mas estratégicos
Pirâmide Muitos unitários na base, integração no meio (quantidade moderada), poucos E2E no topo; equilibra custo, velocidade e valor; evita excesso de testes e manutenção; use a pirâmide como guia, não regra rígida
@ExtendWith(MockitoExtension.class)
class ClienteServiceTest {
    @Mock private ClienteRepository repository;
    @InjectMocks private ClienteService service;

    @Test
    void deveCriarClienteComSucesso() { /* given, when, then */ }
}

Projeto de portfólio

Construa um projeto completo e real, de ponta a ponta, aplicando o que aprendeu, e publique-o para mostrar suas habilidades. Fluxo: Planejamento → Desenvolvimento → Publicação.

Etapa O que fazer
Problema real Escolha um problema relevante; defina o público-alvo e as funcionalidades principais; estude soluções existentes; destaque o diferencial; transforme requisitos em histórias de usuário ("Como um usuário, quero gerenciar minhas tarefas para ser mais produtivo")
Autenticação Login e cadastro de usuários; Spring Security; senhas com BCrypt; proteger endpoints sensíveis; JWT ou sessões; papéis e permissões
CRUD Criar/ler/atualizar/excluir; organizar em Controller, Service e Repository; DTOs; tratar exceções e validar dados; paginação e ordenação; respostas padronizadas
Testes Unitários para regras de negócio; controllers com @WebMvcTest; integração com @SpringBootTest; cenários críticos; automatizados no pipeline
Deploy JAR com Maven/Gradle; Docker; nuvem (Render, Railway, AWS); variáveis de ambiente (banco, JWT); aplicação acessível publicamente
README Objetivo do projeto, funcionalidades, tecnologias, instruções de execução, exemplos de requisições (curl), prints, badges (build, cobertura) e publicação no GitHub

Dica de entrevista: um portfólio com README claro, testes e deploy vale mais do que muitos projetos incompletos. (Ver Comportamento em Entrevistas.)

Revisão geral e trilha de domínio

Trilha final do material: Aprender → Praticar → Publicar. Resumo por área:

Área Pontos-chave
Fundamentos Ecossistema Spring e Spring Boot; ambiente de desenvolvimento; ciclo de vida da aplicação; injeção de dependência; autoconfiguração e starters; boas práticas de projeto
Web / APIs APIs REST com Spring MVC; DTOs e Bean Validation; tratamento de exceções e respostas padronizadas; OpenAPI/Swagger; versionamento e boas práticas de design
Dados Spring Data JPA; entidades e relacionamentos; esquema com Flyway/Liquibase; consultas otimizadas e paginação; boas práticas de performance
Segurança Spring Security; JWT; roles e authorities; proteger rotas e validar permissões; BCrypt; OAuth2 quando necessário
Testes JUnit e Mockito; @WebMvcTest para a camada web; @SpringBootTest para integração; cobertura dos cenários críticos; automatizados no pipeline
Produção JAR + Docker; variáveis de ambiente e segredos; nuvem (AWS, Azure, GCP, Render); monitoramento (logs, métricas, health check); rollback
Observabilidade Logs estruturados (Logback); métricas (Actuator, Prometheus, Grafana); health e readiness; acompanhar logs e métricas em produção

Do zero à aplicação profissional: projeto completo do zero, integração de todas as camadas, boas práticas e arquitetura limpa, testes automatizados e cobertura, Docker e deploy em produção.

Resposta curta para entrevista

"Em Spring Boot eu estruturo a aplicação em camadas (controller, service, repository), uso DTOs e Bean Validation na borda, Spring Data JPA com migrações Flyway, segurança com Spring Security e JWT/OAuth2, testes em pirâmide (JUnit/Mockito, @SpringBootTest, Testcontainers), containerizo com Docker e acompanho a aplicação com Actuator, Prometheus e Grafana — com segredos fora do código e rollback planejado."