Especialização em Backend com Java & Spring Boot • Spring Boot 3 & Java 21 LTS • Spring Data JPA, Security, Microsserviços e Cloud


🗺️ Mapa Conceitual do Tópico

flowchart TD
    A["Classpath do Projeto (Starters)"] --> B["@SpringBootApplication"]
    B --> C["Auto-Configuration (@ConditionalOnClass)"]
    C --> D["ApplicationContext / IoC Container"]
    D --> E["Beans Gerenciados (@Service, @Repository, @Controller)"]
    E --> F["Servidor Embutido (Tomcat) na Porta 8080"]

    subgraph ARQ["Arquitetura do Capítulo"]
        G["Spring Framework: IoC + DI"]
        H["Spring Boot: Convenção sobre Configuração"]
        I["application.yml + Profiles + @ConfigurationProperties"]
    end

    D --> ARQ

    style A fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px
    style B fill:#fff3e0,stroke:#ff9800,stroke-width:2px
    style C fill:#ede7f6,stroke:#7e57c2,stroke-width:2px
    style D fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
    style E fill:#fce4ec,stroke:#e91e63,stroke-width:2px
    style F fill:#f3e5f5,stroke:#9c27b0,stroke-width:2px

🏛️ 1. Fundamentos Técnicos: Spring Framework, Spring Boot e o IoC Container

O Spring Framework resolve um problema antigo do Java corporativo: acoplamento manual entre objetos (new MeuService(new MeuRepository()) espalhado pelo código). Ele introduz o IoC Container (Inversion of Control), materializado na interface ApplicationContext, que passa a ser responsável por instanciar, configurar e injetar as dependências dos Beans da aplicação. Em vez de a classe controlar seu próprio ciclo de vida, o container o controla — daí “inversão”.

O Spring Boot 3 não substitui o Spring Framework: ele o encapsula com convenção sobre configuração. Três mecanismos fazem isso funcionar:

  1. Starter Dependencies (spring-boot-starter-web, spring-boot-starter-data-jpa) são POMs “guarda-chuva” que trazem, de forma testada e compatível entre si, todas as bibliotecas transitivas necessárias para um recurso (ex.: o starter-web traz Tomcat embutido, Jackson e Spring MVC).
  2. Auto-Configuration: ao subir o contexto, o Spring Boot varre classes anotadas com @AutoConfiguration e decide quais Beans registrar usando anotações condicionais — @ConditionalOnClass (só ativa se a biblioteca estiver no classpath), @ConditionalOnMissingBean (só ativa se o desenvolvedor não tiver declarado seu próprio Bean, permitindo sobrescrever o padrão) e @ConditionalOnProperty (ativa/desativa via application.yml).
  3. @SpringBootApplication é uma meta-anotação que combina @Configuration (a classe pode declarar @Bean), @EnableAutoConfiguration (liga o mecanismo acima) e @ComponentScan (varre o pacote atual e subpacotes em busca de @Component, @Service, @Repository, @Controller) — por isso a classe principal deve ficar na raiz do pacote base do projeto.

Configuração externalizada é feita via application.yml/application.properties, mas expor essas propriedades como String soltas espalha “magic strings” pelo código. O padrão correto é o @ConfigurationProperties, hoje idiomático como Java Record (imutável, validável com Bean Validation, sem boilerplate de getters):

@ConfigurationProperties(prefix = "app.security")
public record SecurityProperties(
    String jwtSecret,
    int expirationMinutes,
    boolean enableAudit
) {}

Isso exige @ConfigurationPropertiesScan (ou @EnableConfigurationProperties) habilitado na aplicação para que o record vire um Bean injetável.

Por fim, o próprio ApplicationContext pode ser injetado para introspecção — útil em diagnósticos, métricas customizadas ou frameworks internos que precisam listar Beans dinamicamente via getBeanDefinitionNames() ou getBeansOfType(Classe.class).


💻 2. Código de Demonstração Corporativo

// Application.java — ponto de entrada e Auto-Configuration condicional
package com.empresa.api;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
@ConfigurationPropertiesScan
public class Application implements CommandLineRunner {

    private final ApplicationContext context;

    public Application(ApplicationContext context) {
        this.context = context;
    }

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

    @Override
    public void run(String... args) {
        long totalServices = java.util.Arrays.stream(context.getBeanDefinitionNames())
            .filter(name -> context.getType(name) != null
                && context.getType(name).isAnnotationPresent(org.springframework.stereotype.Service.class))
            .count();
        System.out.printf("Spring Boot 3 inicializado. %d beans de servico registrados.%n", totalServices);
    }
}
// MetricsAutoConfiguration.java — Bean condicional, ativado só se a propriedade permitir
package com.empresa.api.config;

import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MetricsAutoConfiguration {

    @Bean
    @ConditionalOnProperty(name = "app.metrics.enabled", havingValue = "true")
    @ConditionalOnMissingBean
    public MetricsService metricsService() {
        return new MetricsService();
    }

    public static class MetricsService {
        public void registrar(String evento) {
            System.out.println("Metrica registrada: " + evento);
        }
    }
}

O @ConditionalOnMissingBean é o que permite a um desenvolvedor sobrescrever qualquer auto-configuração padrão do Spring Boot simplesmente declarando seu próprio @Bean do mesmo tipo — é a base de como o próprio framework se mantém extensível sem quebrar compatibilidade.