404 Not Found

404 Not Found


nginx

Sua Primeira Aplicação Spring Boot

Uma única anotação @SpringBootApplication é tudo o que é necessário para iniciar toda a aplicação—a mágica do Spring Boot está na combinação engenhosa de três anotações.

1. O Que Você Vai Aprender


2. Uma História Real Sobre um Novo Projeto

(1) Ponto de Dor: Leva meio dia para configurar um projeto

Alice lembrou de sua experiência usando o Spring MVC tradicional quando começou: criar um projeto exigia configurar web.xml, applicationContext.xml e spring-mvc.xml, além de instalar o Tomcat e configurar a fonte de dados JNDI. Apenas fazer o projeto funcionar levava meio dia, sem falar na depuração de ordem de inicialização e problemas de carregamento de beans.

(2) A Solução do Spring Boot

O Spring Boot requer apenas uma anotação e um método main:

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

(3) Resultado

Alice usou o Spring Boot para criar o projeto OrderFlow. Levou apenas 5 minutos desde o início até a primeira resposta da API—sem XML, sem container externo, e os logs de inicialização eram claros e fáceis de ler.


3. Decompondo a Anotação @SpringBootApplication

(1) Uma combinação de três anotações

@SpringBootApplication é uma anotação composta equivalente a usar as três anotações seguintes simultaneamente:

100%
graph TB
    A["@SpringBootApplication"] --> B["@SpringBootConfiguration"]
    A --> C["@EnableAutoConfiguration"]
    A --> D["@ComponentScan"]
    B --> B1["Marks class as<br/>Configuration bean source"]
    C --> C1["Triggers auto-configuration<br/>based on classpath"]
    D --> D1["Scans components<br/>in same package tree"]
Anotação Função Notação Tradicional Equivalente
@SpringBootConfiguration Marca a classe atual como uma classe de configuração @Configuration
@EnableAutoConfiguration Ativa Auto-Configuração @EnableAutoConfiguration
@ComponentScan Scanning de Componentes <context:component-scan>

(2) Regras de scanning do @ComponentScan

@ComponentScan Por padrão, o scanning cobre o pacote que contém a classe principal de inicialização e todos os seus subpacotes.

TEXT
com.orderflow ← O pacote que contém a classe principal de inicialização
├── OrderFlowApplication.java           ← @SpringBootApplication
├── controller/ ← Escaneado por @ComponentScan
│   └── OrderController.java
├── service/ ← Escaneado por @ComponentScan
│   └── OrderService.java
└── repository/ ← Escaneado por @ComponentScan
    └── OrderRepository.java
com.other ← ⚠️ Não incluído no scanning!
🔥 Erro Comum: Se você colocar o Controller em um pacote que está um nível acima ou no mesmo nível do pacote que contém a classe principal de inicialização, o Spring Boot não o escaneará, resultando em um erro 404.


4. Processo de Inicialização do SpringApplication.run()

(1) Sequência de Inicialização

O processo de execução do SpringApplication.run() é um pipeline cuidadosamente projetado:

100%
sequenceDiagram
    participant Main as main()
    participant SA as SpringApplication
    participant Ctx as ApplicationContext
    participant Bean as Beans

    Main->>SA: new SpringApplication()
    SA->>SA: infer Primary Sources
    SA->>SA: check Web Application Type
    SA->>SA: load Initializers & Listeners
    Main->>SA: run(args)
    SA->>SA: create Bootstrap Context
    SA->>SA: prepare Environment
    SA->>SA: print Banner
    SA->>Ctx: create ApplicationContext
    SA->>Ctx: prepare Context (register sources)
    SA->>Ctx: refresh Context
    Ctx->>Bean: instantiate Beans
    Ctx->>Bean: auto-configure
    SA->>SA: call Runners
    SA->>Main: return ApplicationContext

(2) Determinando o Tipo de Aplicação Web

O Spring Boot Detecta Automaticamente o Tipo de Aplicação:

Condição Tipo Container Usado
classpath contém spring-webmvc SERVLET Tomcat / Jetty / Undertow
classpath contém spring-webflux mas não spring-webmvc REACTIVE Netty
Nenhum NONE Sem containers embarcados

(1) ▶ Exemplo: Personalizando a Inicialização do SpringApplication

JAVA
@SpringBootApplication
public class OrderFlowApplication {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(OrderFlowApplication.class);
        app.setBannerMode(Banner.Mode.CONSOLE);
        app.setWebApplicationType(WebApplicationType.SERVLET);
        app.run(args);
    }
}

Saída:

TEXT
// Execução bem-sucedida

5. Formato do Arquivo de Configuração

(1) Properties vs. YAML

O Spring Boot suporta dois formatos de arquivo de configuração que são funcionalmente equivalentes, mas diferem na sintaxe.

(1) ▶ Exemplo: Como escrever application.properties

PROPERTIES
server.port=8080
spring.application.name=orderflow-service
spring.datasource.url=jdbc:mysql://localhost:3306/orderflow
spring.datasource.username=root
spring.datasource.password=secret
spring.jpa.hibernate.ddl-auto=update

Saída:

TEXT
// Execução bem-sucedida

(2) ▶ Exemplo: Como escrever application.yml

YAML
server:
  port: 8080

spring:
  application:
    name: orderflow-service
  datasource:
    url: jdbc:mysql://localhost:3306/orderflow
    username: root
    password: secret
  jpa:
    hibernate:
      ddl-auto: update

Saída:

TEXT
A configuração entrou em vigor.
Dimensão Properties YAML
Estrutura Hierárquica Separada por . Indicação Indica Hierarquia
Legibilidade Pares chave-valor simples, planos Hierarquia clara, adequada para aninhamento
Suporte a Listas list[0]=a - a Mais Intuitivo
Prefixo Repetido Deve ser repetido Prefixo compartilhado no mesmo nível
Desempenho de Parsing Mais rápido Um pouco mais lento (requer parsing de hierarquia)
Prioridade Igual Igual (properties tem precedência quando ambos existem)
⚠️ Nota: Arquivos YAML são muito sensíveis à indentação; você deve usar espaços, não tabs, e a indentação deve ser consistente dentro do mesmo nível.

(2) Referência Rápida de Opções de Configuração Comuns

Opção de Configuração Valor Padrão Descrição
server.port 8080 Porta de Escuta da Aplicação
spring.application.name Nome da Aplicação
server.servlet.context-path / Caminho de Contexto
spring.main.banner-mode console Modo de Exibição do Banner
spring.jpa.show-sql false Imprimir SQL
logging.level.root INFO Nível de Log Global

6. Personalizando o Banner e os Logs de Inicialização

(1) Banner Personalizado

Coloque um banner personalizado em src/main/resources/banner.txt para que seja exibido automaticamente quando o Spring Boot iniciar.

(1) ▶ Exemplo: Banner Personalizado do OrderFlow

TEXT
  ____              _         ____  __
 / ___| _ __   __ _| |_ ___  / ___||  |  ___  _ __
| |    | '_ \ / _` | __/ _ \ \___ \|  |/ _ \| '_ \
| |___ | | | | (_| | ||  __/  ___) |  | (_) | | | |
 \____||_| |_|\__,_|\__\___| |____/|_|\___/|_| |_|

:: OrderFlow Service ::  v${application.version:1.0.0}
:: Spring Boot ${spring-boot.version} ::

Saída:

TEXT
Execução bem-sucedida

(2) Interpretando o Log de Inicialização

TEXT
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_  __ _   \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` |  \ \ \ \
 \\/  ___)| |_)| | | | | | || (_| |  / / / /
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.2.5)

2024-01-15 10:00:01.123  INFO 12345 --- [main] c.o.OrderFlowApplication : Starting OrderFlowApplication
2024-01-15 10:00:03.456  INFO 12345 --- [main] o.s.b.w.e.t.TomcatWebServer : Tomcat initialized with port 8080 (http)
2024-01-15 10:00:04.789  INFO 12345 --- [main] o.s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories
2024-01-15 10:00:06.012  INFO 12345 --- [main] c.o.OrderFlowApplication : Started in 5.123 seconds
Palavras-chave do Log Significado
Starting OrderFlowApplication Aplicação iniciando
Tomcat initialized with port Iniciando Tomcat Embarcado
Bootstrapping Spring Data JPA Configurando Automaticamente o Repositório JPA
Started in X seconds Inicialização concluída, demorou

7. Execute Sua Primeira Interface "Hello OrderFlow"

(1) ▶ Exemplo: Controller Hello OrderFlow

JAVA
package com.orderflow.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;

@RestController
public class HelloController {

    @GetMapping("/api/hello")
    public Map<String, String> hello() {
        return Map.of(
            "message", "Hello, OrderFlow!",
            "timestamp", java.time.Instant.now().toString()
        );
    }
}

Saída:

TEXT
HTTP 200 OK
Content-Type: application/json

{"status":"success","data":{}}
💻 Saída:

TEXT
$ curl http://localhost:8080/api/hello
{"message":"Hello, OrderFlow!","timestamp":"2024-01-15T10:00:00Z"}

(2) ▶ Exemplo: Usando @Value para injeção de configuração

JAVA
@RestController
public class HelloController {

    @Value("${spring.application.name}")
    private String appName;

    @GetMapping("/api/info")
    public Map<String, String> info() {
        return Map.of(
            "application", appName,
            "javaVersion", System.getProperty("java.version")
        );
    }
}

Saída:

TEXT
// Execução bem-sucedida

8. Exemplo Abrangente: Configuração Completa de Inicialização do OrderFlow

JAVA
// src/main/java/com/orderflow/OrderFlowApplication.java
package com.orderflow;

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

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

// src/main/java/com/orderflow/controller/OrderFlowController.java
package com.orderflow.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.Instant;
import java.util.Map;

@RestController
public class OrderFlowController {

    @Value("${spring.application.name:orderflow}")
    private String appName;

    @GetMapping("/api/health")
    public Map<String, Object> health() {
        return Map.of(
            "status", "UP",
            "application", appName,
            "timestamp", Instant.now()
        );
    }
}
YAML
# src/main/resources/application.yml
server:
  port: 8080

spring:
  application:
    name: orderflow-service
💻 Saída:

TEXT
$ curl http://localhost:8080/api/health
{"status":"UP","application":"orderflow-service","timestamp":"2024-01-15T10:00:00Z"}

❓ Perguntas Frequentes

P A anotação @SpringBootApplication pode ser aplicada a qualquer classe?
R Tecnicamente, sim, mas é fortemente recomendado colocá-la no pacote raiz. Isso ocorre porque @ComponentScan escaneia o pacote que contém a classe principal e seus subpacotes por padrão; colocá-la no local errado pode impedir que outros beans sejam descobertos.
P properties e YAML podem coexistir?
R Sim, mas em caso de propriedades duplicadas, a definição properties tem precedência. Recomenda-se usar apenas um para evitar confusão. Recomendamos YAML, pois oferece uma hierarquia mais clara.
P Como desabilito o banner?
R Defina spring.main.banner-mode=off no arquivo de configuração, ou app.setBannerMode(Banner.Mode.OFF) no código.
P O que devo fazer se obtiver o erro "Port 8080 already in use" ao iniciar a aplicação?
R Modifique server.port=8081, ou localize e encerre o processo usando a porta: lsof -i :8080 (Linux/Mac) ou netstat -ano | findstr 8080 (Windows).
P O que causa inicialização lenta?
R Causas comuns: 1) O classpath é muito grande, tornando o scanning demorado; 2) Hibernate ddl-auto=validate causa conexões lentas com bancos de dados remotos; 3) Auto-configurações desnecessárias não foram excluídas. Use o modo --debug para ver detalhes.
P Como especificar a classe principal de entrada?
R Configure usando o <mainClass> no plugin Maven; execute diretamente a classe que contém o método main na IDE; o Spring Boot Maven Plugin detectará automaticamente durante o empacotamento.

📖 Resumo


📝 Exercícios

  1. Exercício Básico (Dificuldade: ⭐): Crie um projeto Spring Boot, personalize o banner.txt, altere a porta do serviço para 9090, e após iniciar o projeto, verifique se o endpoint /api/hello está acessível.

  2. Exercício Avançado (Dificuldade ⭐⭐): Substitua SpringApplication.run() por SpringApplicationBuilder, desative o banner, defina o nível de log para DEBUG, e personalize um endpoint /api/app-info para retornar o nome da aplicação e a versão do Java.

  3. Desafio (Dificuldade: ⭐⭐⭐): Implemente StartupListener e ApplicationListener<ApplicationStartedEvent>, registre o tempo de inicialização da aplicação e imprima-o no log. Reflita sobre a intenção de design por trás do mecanismo de eventos do Spring Boot.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%