Java Framework

Spring Boot

Spring Boot é a camada opinativa sobre o Spring Framework que transforma um monte de configurações em uma aplicação em execução: starters, auto-configuração e um servidor embarcado.

advanced16 min readUpdated 16 de set. de 2026
PostController.java
java
// src/main/java/com/example/blog/PostController.java
@RestController
@RequestMapping("/api/posts")
public class PostController {

    private final PostService postService;

    public PostController(PostService postService) {
        this.postService = postService;
    }

    @GetMapping
    public List<PostResponse> list() {
        return postService.findAll();
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public PostResponse create(@Valid @RequestBody CreatePostRequest request) {
        return postService.create(request);
    }
}
Lançado
2014
Baseado em
Spring Framework
Linguagem
Java, Kotlin, Groovy
Servidor
Embedded Tomcat, Jetty ou Netty
Estilo
Convenção e auto-configuração
Versão
3.x

Por que importa

Por que o Spring Boot domina a JVM

Executando em minutos

Um starter e um método main entregam uma aplicação pronta para produção com um servidor embarcado, então não há nada para fazer deploy antes de escrever o código.

Auto-configuração

O Spring Boot inspeciona o classpath e configura os beans que encontra. Adicione um driver de banco de dados e um DataSource aparece, pronto para uso.

Um ecossistema coerente

Spring Data, Security, Batch, Integration e Cloud compartilham o mesmo modelo de programação, então as habilidades são transferíveis por toda a plataforma.

O panorama completo

Auto-config, DI, starters

Starters trazem dependências coerentes, a auto-configuração as conecta a partir de padrões sensatos, e o container injeta os objetos que suas classes precisam.

Auto-configuração

Bootstrap

A configuração condicional lê o que está no classpath e fornece padrões, que você sobrescreve com propriedades em vez de código.

Camada web anotada

Expor

Anotações mapeiam métodos HTTP e caminhos para métodos Java, e conversores de mensagem transformam objetos em JSON automaticamente.

Spring Data JPA

Persistir

Interfaces de repositório oferecem CRUD, métodos de consulta e paginação sem a necessidade de implementações escritas à mão.

HTML5 de uma olhada

A caixa de ferramentas do Spring Boot

Servidor embarcado

Tomcat, Jetty ou Netty rodam dentro do processo como uma biblioteca Java comum.

Starters

O spring-boot-starter-web traz toda a stack web em uma única dependência.

Anotações

@RestController, @GetMapping e @RequestBody descrevem a API.

Injeção de dependência

O contexto da aplicação cria e conecta beans via injeção por construtor.

Spring Data JPA

Interfaces de repositório substituem o código repetitivo de acesso a dados.

Actuator

Endpoints de saúde, métricas e informações estão a apenas uma dependência de distância.

Uma breve historia

Do Spring XML a um main de uma linha

  1. 2012

    Spring Boot é anunciado

    A equipe do Spring apresenta uma forma de iniciar aplicações sem o XML que havia crescido em torno do framework.

    12
  2. 2014

    Spring Boot 1.0

    O primeiro lançamento GA torna os starters, a auto-configuração e o servidor embarcado a maneira padrão de construir apps Spring.

    14
  3. 2018

    Spring Boot 2.0

    O Spring 5 traz o WebFlux, um Actuator reescrito e suporte de primeira classe para Kotlin.

    18
  4. 2022

    Spring Boot 3.0

    Java 17 torna-se a base, o namespace jakarta substitui o javax, e as imagens nativas do GraalVM amadurecem.

    22
  5. 2024

    Spring Boot 3.4

    Logging estruturado, observabilidade aprimorada e baselines de dependências atualizadas mantêm a plataforma atual.

    24
  6. Hoje

    A stack JVM padrão

    O Spring Boot é o ponto de partida presumido para novos serviços Java, de monolitos a microsserviços cloud-native.

    Hoje

O guia completo

Spring Boot: Tudo que voce precisa saber

O que é Spring Boot?

O Spring Boot é uma camada sobre o Spring Framework que elimina a configuração que o Spring exigia antigamente. Em vez de arquivos XML, configuração de servlets e a necessidade de um container para deploy, você escreve uma classe com um método main, adiciona uma dependência starter e obtém uma aplicação em execução com um servidor embarcado.

Três conceitos fazem o trabalho pesado. Os Starters agrupam as dependências de uma funcionalidade em apenas uma linha. A Auto-configuration inspeciona o classpath e configura beans com base em padrões sensatos. O servidor embarcado significa que a aplicação é um processo Java normal — não há nada para instalar ou onde fazer o deploy.

O resultado é que o Spring Boot se tornou a maneira padrão de construir serviços JVM, desde pequenas APIs internas até grandes frotas de microserviços, mantendo todo o poder do ecossistema Spring por baixo.

O ecossistema Spring em um minuto

O Spring não é apenas uma biblioteca, mas sim uma família que compartilha o mesmo modelo de programação:

  • Spring Framework — o container core, injeção de dependência e a camada web.
  • Spring Data — repositórios para bancos SQL e NoSQL.
  • Spring Security — autenticação e autorização.
  • Spring Batch / Integration — processamento em lote e mensageria.
  • Spring Cloud — configuração, discovery e resiliência para sistemas distribuídos.

Como foram projetados em conjunto, um projeto pode adotá-los gradualmente sem precisar alterar a forma como o código é escrito. Essa consistência é o real motivo pelo qual as equipes padronizam seus projetos com Spring.

Starters e gerenciamento de dependências

Um starter é um conjunto curado de dependências que funcionam juntas. Você declara a funcionalidade, e não os jars individuais.

<!-- pom.xml -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

O equivalente no Gradle é igualmente curto:

dependencies {
  implementation "org.springframework.boot:spring-boot-starter-web"
  implementation "org.springframework.boot:spring-boot-starter-data-jpa"
  implementation "org.springframework.boot:spring-boot-starter-validation"
  runtimeOnly "org.postgresql:postgresql"
}

O POM pai ou o plugin de dependency-management define as versões compatíveis para você. Sobrescreva uma versão apenas quando houver um motivo, e deixe a plataforma gerenciar o restante.

A classe da aplicação e o servidor embarcado

Toda aplicação Spring Boot começa aqui. Esta única classe é suficiente para iniciar um servidor web.

package com.example.blog;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class BlogApplication {
    public static void main(String[] args) {
        SpringApplication.run(BlogApplication.class, args);
    }
}

@SpringBootApplication combina três anotações: @Configuration, @EnableAutoConfiguration e @ComponentScan. O escaneamento de componentes (component scanning) começa no pacote desta classe e segue para baixo, por isso a classe principal deve ficar na raiz da estrutura de pacotes do seu projeto.

Executar ./mvnw spring-boot:run inicia um Tomcat embarcado na porta 8080. Você pode trocá-lo por Jetty ou Netty apenas alterando uma dependência, e o código da aplicação permanece inalterado.

A camada web anotada

O Spring MVC mapeia requisições HTTP para métodos utilizando anotações. @RestController combina @Controller e @ResponseBody, fazendo com que os objetos retornados sejam serializados para JSON pelo Jackson.

@RestController
@RequestMapping("/api/posts")
public class PostController {

    private final PostService service;

    public PostController(PostService service) {
        this.service = service;
    }

    @GetMapping
    public List<PostResponse> list(
            @RequestParam(defaultValue = "0") int page) {
        return service.findPage(page);
    }

    @GetMapping("/{id}")
    public PostResponse get(@PathVariable Long id) {
        return service.findById(id);
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public PostResponse create(@Valid @RequestBody CreatePostRequest request) {
        return service.create(request);
    }

    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void delete(@PathVariable Long id) {
        service.delete(id);
    }
}

@PathVariable lê da URL, @RequestParam da query string, e @RequestBody desserializa o payload. Mantenha os controllers enxutos: eles devem traduzir o HTTP em uma chamada de serviço e traduzir o resultado de volta. A lógica de domínio pertence à camada de serviço.

Injeção de dependência e o contexto da aplicação

O application context é o container que cria objetos, chamados de beans, e fornece suas dependências. Você declara o que uma classe precisa; o Spring decide como construí-la.

@Service
public class PostService {

    private final PostRepository repository;
    private final Clock clock;

    public PostService(PostRepository repository, Clock clock) {
        this.repository = repository;
        this.clock = clock;
    }

    @Transactional
    public PostResponse create(CreatePostRequest request) {
        var post = new Post(request.title(), request.body(), clock.instant());
        return PostResponse.from(repository.save(post));
    }
}

Anotações de estereótipo marcam as classes a serem gerenciadas: @Component para beans genéricos, @Service para serviços de domínio, @Repository para acesso a dados e @RestController para endpoints web. Para qualquer coisa que você não possa anotar — como uma classe de terceiros ou um cliente configurado — declare-a em uma classe @Configuration.

@Configuration
class ClockConfig {

    @Bean
    Clock clock() {
        return Clock.systemUTC();
    }
}

Prefira a injeção via construtor em todos os lugares. Isso torna as dependências explícitas, permite o uso de campos final e permite que você instancie a classe em um teste unitário simples sem precisar iniciar o Spring.

Spring Data JPA e o banco de dados

As entidades mapeiam objetos Java para tabelas, e os repositórios fornecem acesso aos dados sem a necessidade de uma implementação.

@Entity
@Table(name = "posts")
public class Post {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, length = 120)
    private String title;

    @Column(nullable = false)
    private String body;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    private Author author;

    protected Post() {
    }

    public Post(String title, String body, Author author) {
        this.title = title;
        this.body = body;
        this.author = author;
    }

    // getters and domain methods
}
public interface PostRepository extends JpaRepository<Post, Long> {

    List<Post> findByPublishedTrueOrderByCreatedAtDesc();

    @Query("select p from Post p join fetch p.author where p.id = :id")
    Optional<Post> findWithAuthor(Long id);
}

O Spring Data deriva uma query a partir do nome do método, portanto findByPublishedTrueOrderByCreatedAtDesc não precisa de corpo. Use @Query quando o nome derivado for ilegível, e join fetch para evitar o problema de N+1 do lazy-loading. Mantenha ddl-auto como validate em produção e gerencie o schema com Flyway ou Liquibase.

Configuração com application.yml e profiles

A configuração reside em src/main/resources e pode ser sobrescrita por variáveis de ambiente, o que permite que o mesmo jar seja executado em qualquer lugar.

# src/main/resources/application.yml
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/blog
    username: blog
    password: ${DB_PASSWORD}
  jpa:
    hibernate:
      ddl-auto: validate
    open-in-view: false
server:
  port: 8080

Os profiles permitem que a mesma build se comporte de maneira diferente dependendo do ambiente.

# src/main/resources/application-prod.yml
spring:
  datasource:
    url: ${DATABASE_URL}
logging:
  level:
    root: warn

Ative um profile com --spring.profiles.active=prod ou através da variável de ambiente SPRING_PROFILES_ACTIVE. @ConfigurationProperties vincula um grupo de configurações a uma classe tipada, o que é mais seguro do que espalhar anotações @Value por todo o código.

Validação

As constraints do Jakarta Bean Validation em um objeto de requisição são aplicadas quando o parâmetro do controller é anotado com @Valid.

public record CreatePostRequest(
        @NotBlank @Size(max = 120) String title,
        @NotBlank String body
) {
}

Um @RestControllerAdvice centraliza a resposta de erro para que todos os endpoints retornem o mesmo formato.

@RestControllerAdvice
public class ApiExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Map<String, String> onValidation(MethodArgumentNotValidException ex) {
        return ex.getBindingResult().getFieldErrors().stream()
                .collect(Collectors.toMap(
                        FieldError::getField,
                        FieldError::getDefaultMessage,
                        (first, second) -> first));
    }
}

Valide na fronteira e permita que o domínio confie em suas entradas. Combinado com um exception handler consistente, isso remove verificações repetitivas de if (input == null) de cada serviço.

Spring Security em resumo

O Spring Security é uma cadeia de filtros (filter chain) posicionada à frente da sua aplicação. No Spring Boot moderno, você o configura através de um bean em vez de XML.

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .csrf(csrf -> csrf.disable())
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/actuator/health").permitAll()
                        .anyRequest().authenticated())
                .oauth2ResourceServer(oauth -> oauth.jwt(Customizer.withDefaults()));
        return http.build();
    }
}

Esse único bean exige um JWT válido em todos os endpoints, exceto no health check. Regras a nível de método com @PreAuthorize adicionam autorização granular onde for necessário. Segurança é um tema complexo — planeje ler a documentação cuidadosamente antes de expor qualquer coisa na internet.

Actuator: saúde e métricas

Adicionar o starter do Actuator expõe endpoints operacionais gratuitamente.

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics
  endpoint:
    health:
      show-details: always
curl localhost:8080/actuator/health

/actuator/health integra-se com probes de liveness e readiness, e /actuator/metrics reporta estatísticas de JVM, HTTP e datasource. Exponha apenas o que for necessário e proteja o restante — esses endpoints revelam muitos detalhes sobre um sistema em execução.

Testes

@SpringBootTest inicia o contexto da aplicação e serve como base para testes de integração. MockMvc exercita a camada web sem abrir uma porta real.

@SpringBootTest
@AutoConfigureMockMvc
class PostControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void listsPosts() throws Exception {
        mockMvc.perform(get("/api/posts"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$[0].title").value("Hello"));
    }
}

Para um feedback mais rápido, fragmente o contexto apenas para a camada sob teste e utilize mocks para os colaboradores.

@WebMvcTest(PostController.class)
class PostControllerSliceTest {

    @Autowired
    private MockMvc mockMvc;

    @MockitoBean
    private PostService service;

    @Test
    void returnsNotFound() throws Exception {
        given(service.findById(1L)).willThrow(new PostNotFoundException(1L));
        mockMvc.perform(get("/api/posts/1"))
                .andExpect(status().isNotFound());
    }
}

Use slices para controllers e repositories, e reserve o contexto completo para alguns testes end-to-end. O Testcontainers fornece um banco de dados real nos testes sem a necessidade de mockar a persistência.

Build e deploy

O build gera um executable fat jar que contém suas classes, dependências e o servidor embarcado.

./mvnw clean package
java -jar target/blog-0.0.1-SNAPSHOT.jar

Para containers, o Buildpacks cria uma imagem otimizada sem a necessidade de um Dockerfile.

./mvnw spring-boot:build-image

A configuração vem do ambiente, portanto, o mesmo artefato move-se de staging para produção sem alterações. Adicione um Dockerfile apenas quando precisar de controles que o Buildpacks não oferece, e prefira um multi-stage build para manter a imagem compacta.

Melhores práticas

  • Organize os pacotes por funcionalidade (package by feature) para que cada domínio possua seu próprio controller, service e repository.
  • Use injeção via construtor e mantenha os campos final.
  • Retorne DTOs nos controllers em vez de entidades JPA.
  • Valide os objetos de requisição com @Valid e trate os erros em um único @RestControllerAdvice.
  • Mantenha o ddl-auto em validate e gerencie as alterações de schema com Flyway ou Liquibase.
  • Externalize a configuração e utilize profiles em vez de recompilar para cada ambiente.
  • Adicione o Actuator, então exponha e proteja apenas os endpoints que você realmente precisa.

Erros comuns

  • Injeção de campo com @Autowired, o que oculta dependências e complica os testes.
  • Serializar entidades diretamente, expondo lazy-loading ou colunas internas.
  • Permitir que os controllers acumulem lógica de negócio em vez de delegá-la para services.
  • Usar ddl-auto: update em produção, causando divergências em relação ao schema real.
  • Iniciar todo o contexto em cada teste unitário, tornando a suíte de testes lenta.
  • Expor todos os endpoints do Actuator para a internet pública.
  • Adicionar starters desnecessários e pagar o preço disso no tempo de startup.

Próximos passos

O Spring Boot ensina injeção de dependência, auto-configuração e design em camadas — conceitos que vão muito além do Java. Se você gostou do modelo de módulos e injeção, o NestJS aplica isso em TypeScript, enquanto o Express mostra a alternativa minimalista. A camada web anotada é, fundamentalmente, uma REST API, e a maioria das aplicações persiste dados em um armazenamento relacional, tornando o PostgreSQL o próximo passo natural.

Injetando dependências

A injeção por construtor torna os colaboradores obrigatórios explícitos, mantém os campos como final e permite testar a classe sem iniciar o Spring.

Preferir
@Service
public class PostService {

    private final PostRepository repository;

    public PostService(PostRepository repository) {
        this.repository = repository;
    }
}
Evitar
@Service
public class PostService {

    @Autowired
    private PostRepository repository;
    // hidden dependency, hard to test in isolation
}

Retornando dados de controllers

Expor entidades JPA acopla sua API ao esquema do banco. Mapeie para um DTO para que campos lazy, colunas internas e migrações futuras permaneçam privados.

Preferir
@GetMapping("/{id}")
public PostResponse get(@PathVariable Long id) {
    return service.findById(id);
}
Evitar
@GetMapping("/{id}")
public Post get(@PathVariable Long id) {
    return repository.findById(id).orElseThrow();
    // serialising the entity leaks the schema
}

Trade-offs

O Spring Boot vale o peso?

O Spring Boot recompensa equipes que desejam uma plataforma integrada e comprovada. O custo é o tempo de inicialização, memória e uma grande área de aprendizado.

Strengths

  • Tudo já está integrado

    Web, dados, segurança, validação, mensageria e observabilidade compartilham um único modelo de configuração, então raramente você precisa conectar bibliotecas manualmente.

  • O ecossistema e o mercado de contratação são enormes

    É a stack Java corporativa padrão. Bibliotecas focam nele primeiro, e encontrar desenvolvedores experientes é fácil.

  • Recursos de produção são de primeira classe

    Actuator, configuração externalizada, profiles e métricas tratam a operação como uma preocupação de design, não como um detalhe posterior.

Trade-offs

  • Custo de inicialização e memória

    Um serviço Spring Boot inicia mais lentamente e usa mais memória do que um framework minimalista. Em serverless ou muitos serviços pequenos, esse overhead é real.

  • A curva de aprendizado é íngreme

    A auto-configuração esconde muita coisa. Quando o padrão está errado, você precisa entender o contexto do Spring subjacente para depurá-lo.

  • A 'mágica' das anotações pode obscurecer o fluxo

    O comportamento está espalhado por anotações, aspectos e proxies. Seguir uma requisição de ponta a ponta requer prática e boas ferramentas.

Perguntas frequentes

Perguntas frequentes

Keep learning

Related topics from the roadmap.

$ comecar a aprender

Pronto para aprender Spring Boot?

Nosso tutorial interativo te guia por Spring Boot passo a passo — com quizzes e codigo real que voce pode executar no navegador.