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:
- Acesse
start.spring.io. - Escolha o projeto (Maven ou Gradle — ambos são suportados).
- Escolha a linguagem (Java) e uma versão estável (17 ou 21).
- Preencha os metadados: group (ex.:
com.exemplo), artifact (ex.:minha-api), name e package. - Adicione as dependências (ex.: Spring Web para a primeira API); outras podem vir depois.
- Clique em Generate (baixa um
.zip) e extraia. - Importe o projeto na IDE e aguarde a resolução das dependências.
- Execute a classe
Application(commain) e procure a mensagemStartedno 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 packagee execute comjava -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:
newespalhado, campos estáticos e injeção por campo (@Autowireddireto 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) |
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 aopom.xmloubuild.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
JpaRepositorye o Spring Data a implementa automaticamente. - CRUD pronto:
save,findById,findAll,delete… - Transação: garante uma operação consistente no banco; usa
@Transactionalem serviços ou métodos e faz rollback automático em caso de erro.
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
mappedByno lado inverso, mantendo consistência e evitando atualizações duplicadas. fetch: define como os relacionados são carregados —LAZY(sob demanda, recomendado) ouEAGER(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.
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.
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
@Schemae@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 |
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 |
(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 |
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/DELETEou headers personalizados, o navegador envia antes uma requisiçãoOPTIONS; 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@CrossOriginno 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 |
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)— otrueindica 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
@EnableSchedulingna aplicação e anote o método com@Scheduled; o método deve servoide 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) einitialDelay, 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 |
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.
| 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 |
- 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
Warningavisando 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
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 } }
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_historyregistra 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 |
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 |
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 |
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+HandlerFunctiondefinem as rotas sem anotações. WebClient: cliente HTTP reativo (substitui oRestTemplate):webClient.get().uri("/x").retrieve().bodyToMono(Resposta.class).timeout(Duration.ofSeconds(2)).- Streaming:
produces = MediaType.TEXT_EVENT_STREAM_VALUEdevolve umFluxcomo 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) eWebTestClient.
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
allowedOriginse 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-composedetecta e liga os serviços); a imagem da aplicação nasce de umDockerfilesimples 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 |
# 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 = trueem@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.
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"]
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."