Spring Boot 3.4: Todas as novidades explicadas

Spring Boot 3.4 traz logging estruturado nativo, virtual threads estendidos, graceful shutdown por padrão e MockMvcTester. Guia completo das novas funcionalidades.

Novas funcionalidades e melhorias do Spring Boot 3.4

Spring Boot 3.4, lançado em novembro de 2024, traz melhorias significativas em produtividade e desempenho de aplicações. Esta versão introduz logging estruturado nativo, habilita graceful shutdown por padrão e amplia o suporte a virtual threads em todo o framework.

Pré-requisitos

Spring Boot 3.4 requer Java 17 no mínimo e suporta Java 21 para virtual threads. Esta versão utiliza o Spring Framework 6.2.

Logging estruturado nativo

O logging estruturado representa um avanço importante para a observabilidade de aplicações. Em vez de logs baseados em texto difíceis de analisar, o Spring Boot 3.4 gera logs em formato JSON consumíveis por ferramentas como Elasticsearch, Grafana Loki ou Datadog.

Três formatos são suportados nativamente: Elastic Common Schema (ECS), Logstash e Graylog Extended Log Format (GELF).

properties
# application.properties
# Enable structured logging in console
logging.structured.format.console=ecs

# Or for log files
logging.structured.format.file=logstash

Essa configuração simples produz logs JSON estruturados automaticamente.

LoggingController.javajava
@RestController
@RequestMapping("/api/demo")
public class LoggingController {

    // Logger injection via SLF4J
    private static final Logger logger = LoggerFactory.getLogger(LoggingController.class);

    @GetMapping("/action")
    public ResponseEntity<String> performAction(@RequestParam String userId) {
        // Log will be automatically formatted as structured JSON
        logger.info("Action performed by user: {}", userId);
        return ResponseEntity.ok("Action completed");
    }
}

Com o formato ECS habilitado, esse log se torna um objeto JSON contendo timestamp, nível, mensagem, nome da classe, thread e metadados da aplicação. Essa estrutura simplifica a busca e agregação em plataformas de monitoramento.

Graceful Shutdown habilitado por padrão

Mudança importante: o graceful shutdown agora está habilitado por padrão. As requisições HTTP em andamento são processadas antes do encerramento do servidor, evitando erros 502 durante deploys.

properties
# application.properties
# Graceful shutdown is now ON by default
# To restore previous behavior (immediate shutdown):
server.shutdown=immediate

# Configure maximum wait timeout (30s default)
spring.lifecycle.timeout-per-shutdown-phase=45s

Esse comportamento se aplica a todos os servidores embarcados: Tomcat, Jetty, Undertow e Reactor Netty.

LifecycleConfig.javajava
@Configuration
public class LifecycleConfig {

    private static final Logger logger = LoggerFactory.getLogger(LifecycleConfig.class);

    @Bean
    public ApplicationListener<ContextClosedEvent> gracefulShutdownListener() {
        // This listener executes at shutdown start
        return event -> {
            logger.info("Graceful shutdown initiated - completing in-flight requests");
            // Custom logic: close connections, save state, etc.
        };
    }
}

Essa melhoria simplifica a implementação de deploys sem downtime, sem necessidade de configuração adicional na maioria dos casos.

Suporte estendido a Virtual Threads

O Spring Boot 3.4 estende o suporte a virtual threads (Java 21+) para mais componentes. OtlpMeterRegistry e o servidor Undertow agora utilizam virtual threads quando habilitados.

properties
# application.properties
# Enable virtual threads globally
spring.threads.virtual.enabled=true

Essa única propriedade transforma o modelo de threads da aplicação. Cada requisição HTTP recebe sua própria virtual thread, permitindo milhares de conexões simultâneas sem esgotar o pool de threads.

AsyncService.javajava
@Service
public class AsyncService {

    private static final Logger logger = LoggerFactory.getLogger(AsyncService.class);

    // With virtual threads enabled, each blocking call
    // no longer consumes an OS thread
    public String fetchExternalData() {
        logger.info("Executing on thread: {}", Thread.currentThread());

        // Blocking HTTP call - with virtual threads,
        // the OS thread is released during I/O wait
        return restClient.get()
            .uri("https://api.external.com/data")
            .retrieve()
            .body(String.class);
    }
}

As virtual threads se destacam em aplicações com alta carga de I/O: chamadas HTTP, consultas a bancos de dados, operações com arquivos. A thread do sistema operacional é liberada durante o tempo de espera e reatribuída ao retomar.

Compatibilidade

As virtual threads requerem Java 21 no mínimo. No Java 17, essa propriedade é ignorada e o comportamento clássico se aplica.

RestClient e RestTemplate aprimorados

O Spring Boot 3.4 normaliza a configuração do cliente HTTP. A seleção de HttpRequestFactory agora segue uma precedência clara baseada no classpath.

HttpClientConfig.javajava
@Configuration
public class HttpClientConfig {

    @Bean
    public RestClient restClient(RestClient.Builder builder) {
        // Spring Boot automatically chooses implementation:
        // 1. Apache HTTP Components (if present)
        // 2. Jetty Client
        // 3. Reactor Netty
        // 4. JDK HttpClient (Java 11+)
        // 5. SimpleClientHttpRequestFactory (fallback)
        return builder
            .baseUrl("https://api.example.com")
            .defaultHeader("Accept", "application/json")
            .build();
    }
}

A configuração do comportamento de redirecionamentos também é simplificada.

properties
# application.properties
# Force specific implementation
spring.http.client.factory=jdk

# Configure redirect behavior
spring.http.client.redirects=dont-follow

Para controle mais detalhado, o novo ClientHttpRequestFactoryBuilder permite configuração programática completa.

CustomHttpClientConfig.javajava
@Configuration
public class CustomHttpClientConfig {

    @Bean
    public RestClient customRestClient(ClientHttpRequestFactoryBuilder factoryBuilder) {
        // Advanced factory configuration
        ClientHttpRequestFactory factory = factoryBuilder
            .httpComponents()
            .connectTimeout(Duration.ofSeconds(5))
            .readTimeout(Duration.ofSeconds(30))
            .build();

        return RestClient.builder()
            .requestFactory(factory)
            .baseUrl("https://api.example.com")
            .build();
    }
}

Essa abordagem oferece máxima flexibilidade mantendo uma API consistente independentemente da implementação HTTP subjacente.

Pronto para mandar bem nas entrevistas de Spring Boot?

Pratique com nossos simuladores interativos, flashcards e testes tecnicos.

MockMvcTester para testes fluentes

O Spring Boot 3.4 introduz o MockMvcTester, uma alternativa baseada em AssertJ ao MockMvc. Essa nova abordagem torna os testes mais legíveis e expressivos.

UserControllerTest.javajava
@WebMvcTest(UserController.class)
class UserControllerTest {

    @Autowired
    private MockMvcTester mockMvc; // New class!

    @Test
    void shouldReturnUserById() {
        // Fluent API with AssertJ
        mockMvc.get().uri("/api/users/{id}", 1)
            .assertThat()
            .hasStatusOk()
            .hasContentType(MediaType.APPLICATION_JSON)
            .bodyJson()
            .extractingPath("$.name")
            .isEqualTo("John Doe");
    }

    @Test
    void shouldReturn404ForUnknownUser() {
        mockMvc.get().uri("/api/users/{id}", 999)
            .assertThat()
            .hasStatus(HttpStatus.NOT_FOUND)
            .bodyJson()
            .extractingPath("$.error")
            .isEqualTo("User not found");
    }
}

Comparado com a abordagem anterior usando MockMvc, as asserções são mais concisas e o encadeamento se torna mais natural.

ComparisonTest.javajava
@WebMvcTest(UserController.class)
class ComparisonTest {

    @Autowired
    private MockMvcTester mockMvcTester;

    @Autowired
    private MockMvc mockMvc;

    @Test
    void withMockMvcTester() {
        // New approach: fluent and concise
        mockMvcTester.post().uri("/api/users")
            .contentType(MediaType.APPLICATION_JSON)
            .content("{\"name\": \"Jane\"}")
            .assertThat()
            .hasStatus(HttpStatus.CREATED)
            .hasHeader("Location", "/api/users/2");
    }

    @Test
    void withClassicMockMvc() throws Exception {
        // Old approach: more verbose
        mockMvc.perform(post("/api/users")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{\"name\": \"Jane\"}"))
            .andExpect(status().isCreated())
            .andExpect(header().string("Location", "/api/users/2"));
    }
}

O MockMvcTester é configurado automaticamente quando o AssertJ está presente no classpath (incluído por padrão com spring-boot-starter-test).

Docker Compose e Testcontainers aprimorados

O suporte ao Docker Compose ganha flexibilidade com múltiplos arquivos de configuração e argumentos personalizados.

properties
# application.properties
# Use multiple Docker Compose files
spring.docker.compose.file=compose.yaml,compose-dev.yaml

# Pass arguments at startup
spring.docker.compose.start.arguments=--scale redis=2

# Arguments at shutdown
spring.docker.compose.stop.arguments=--timeout 60

Novos serviços são detectados e configurados automaticamente.

yaml
# compose.yaml
services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    ports:
      - "5432:5432"

  redis-stack:
    image: redis/redis-stack:latest
    ports:
      - "6379:6379"
      - "8001:8001" # RedisInsight UI

  grafana-lgtm:
    image: grafana/otel-lgtm:latest
    ports:
      - "3000:3000"  # Grafana
      - "4317:4317"  # OTLP gRPC

O Spring Boot 3.4 detecta automaticamente esses serviços e configura as propriedades de conexão correspondentes.

Para testes com Testcontainers, novos containers são suportados.

IntegrationTestConfig.javajava
@TestConfiguration(proxyBeanMethods = false)
public class IntegrationTestConfig {

    @Bean
    @ServiceConnection
    public PostgreSQLContainer<?> postgresContainer() {
        return new PostgreSQLContainer<>("postgres:16");
    }

    @Bean
    @ServiceConnection
    public RedisStackContainer redisStackContainer() {
        // New Redis Stack support
        return new RedisStackContainer("redis/redis-stack:latest");
    }

    @Bean
    @ServiceConnection
    public LgtmStackContainer observabilityContainer() {
        // New Grafana LGTM support (Loki, Grafana, Tempo, Mimir)
        return new LgtmStackContainer("grafana/otel-lgtm:latest");
    }
}

A anotação @ServiceConnection configura automaticamente as propriedades de conexão, eliminando a necessidade de @DynamicPropertySource na maioria dos casos.

Actuator SSL e observabilidade

O novo endpoint /actuator/info agora expõe informações sobre os certificados SSL configurados: datas de validade, emissor e assunto.

properties
# application.properties
# Enable SSL information in actuator
management.info.ssl.enabled=true

# Configure warning threshold for expiring certificates
management.health.ssl.certificate-validity-warning-threshold=30d

Essa funcionalidade permite monitorar a expiração de certificados diretamente via actuator, facilitando a automação de renovações.

SslMonitoringConfig.javajava
@Configuration
public class SslMonitoringConfig {

    @Bean
    public HealthIndicator sslCertificateHealth(SslInfo sslInfo) {
        return () -> {
            // Custom certificate validity check
            boolean allValid = sslInfo.getBundles().values().stream()
                .flatMap(bundle -> bundle.getCertificates().stream())
                .allMatch(cert -> cert.getValidityEnds().isAfter(Instant.now()));

            return allValid
                ? Health.up().build()
                : Health.down().withDetail("reason", "Certificate expiring soon").build();
        };
    }
}

Para observabilidade, o transporte OTLP agora suporta gRPC além de HTTP.

properties
# application.properties
# Use gRPC for OTLP (traces and metrics)
management.otlp.tracing.transport=grpc
management.otlp.tracing.endpoint=http://localhost:4317

# New: group applications together
spring.application.group=payment-services

O grupo de aplicação (spring.application.group) permite agrupar logicamente múltiplos serviços em dashboards de observabilidade.

Imagens OCI mais leves

O builder de imagens OCI padrão muda de paketobuildpacks/builder-jammy-base para paketobuildpacks/builder-jammy-java-tiny, produzindo imagens significativamente menores.

build.gradlegroovy
tasks.named("bootBuildImage") {
    // Native ARM support (new)
    imagePlatform = "linux/arm64"

    // New security flag
    trustBuilder = false

    // Image configuration
    imageName = "myregistry.com/myapp:${version}"
}

O novo parâmetro imagePlatform simplifica builds multiplataforma para ARM e x64.

xml
<!-- pom.xml -->
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <image>
            <!-- Native ARM support -->
            <platform>linux/arm64</platform>
            <!-- Builder optimized for minimal images -->
            <builder>paketobuildpacks/builder-jammy-java-tiny</builder>
        </image>
    </configuration>
</plugin>

Essas imagens otimizadas iniciam mais rápido e consomem menos recursos, especialmente benéfico para deploys em Kubernetes.

Nota de migração

A mudança de builder pode afetar aplicações que dependem de certas ferramentas do sistema. Recomenda-se testar as novas imagens antes de fazer deploy em produção.

Mudanças no Bean Validation

O Spring Boot 3.4 alinha o comportamento de validação com a especificação do Bean Validation. A validação não se propaga mais automaticamente para propriedades aninhadas.

ConfigProperties.javajava
@ConfigurationProperties(prefix = "app")
@Validated
public class AppConfig {

    @NotBlank
    private String name;

    // IMPORTANT: @Valid required to cascade validation
    @Valid
    private DatabaseConfig database;

    // Without @Valid, ServerConfig constraints will NOT be checked
    private ServerConfig server;

    // Getters and setters
}

public class DatabaseConfig {
    @NotBlank
    private String url;

    @Min(1)
    private int poolSize;

    // Getters and setters
}

public class ServerConfig {
    @NotNull // This constraint will NOT be checked without @Valid on parent
    private Integer port;

    // Getters and setters
}

Essa mudança pode afetar aplicações existentes. Recomenda-se auditar as classes @ConfigurationProperties e adicionar @Valid onde a validação deve se propagar.

Deprecação de @MockBean e @SpyBean

As anotações @MockBean e @SpyBean do Spring Boot estão deprecadas em favor das novas anotações do Mockito.

UserServiceTest.java (new approach)java
@SpringBootTest
class UserServiceTest {

    // New: native Mockito annotations
    @MockitoBean
    private UserRepository userRepository;

    @MockitoSpyBean
    private EmailService emailService;

    @Autowired
    private UserService userService;

    @Test
    void shouldCreateUser() {
        // Mock configuration
        when(userRepository.save(any())).thenReturn(new User(1L, "test@example.com"));

        userService.createUser("test@example.com");

        // Spy verification
        verify(emailService).sendWelcomeEmail("test@example.com");
    }
}

As anotações antigas ainda funcionam mas exibem avisos de deprecação. Recomenda-se planejar a migração para @MockitoBean e @MockitoSpyBean.

Comece a praticar!

Teste seus conhecimentos com nossos simuladores de entrevista e testes tecnicos.

Conclusão

O Spring Boot 3.4 oferece melhorias substanciais em produtividade e observabilidade:

Checklist de migração:

  • Habilitar logging estruturado para melhorar a observabilidade
  • Verificar o comportamento do graceful shutdown (agora habilitado por padrão)
  • Considerar virtual threads para aplicações com alta carga de I/O (Java 21+)
  • Migrar para MockMvcTester para testes mais legíveis
  • Adicionar @Valid em propriedades @ConfigurationProperties aninhadas
  • Substituir @MockBean/@SpyBean por @MockitoBean/@MockitoSpyBean
  • Testar as novas imagens OCI antes do deploy em produção

O Spring Boot 3.4 consolida sua posição como o framework de referência para o desenvolvimento Java moderno, com atenção especial aos padrões de observabilidade e desempenho.

Fontes:

Tags

#spring boot
#java
#spring boot 3.4
#spring framework
#backend

Compartilhar

Artigos relacionados