# Spring Boot 3.4: Tutte le novità spiegate > Spring Boot 3.4 introduce logging strutturato nativo, virtual threads estesi, graceful shutdown predefinito e MockMvcTester. Guida completa alle nuove funzionalità. - Published: 2026-01-16 - Updated: 2026-04-10 - Author: SharpSkill - Tags: spring boot, java, spring boot 3.4, spring framework, backend - Reading time: 12 min --- Spring Boot 3.4, rilasciato a novembre 2024, offre miglioramenti significativi in termini di produttività e performance delle applicazioni. Questa versione introduce il logging strutturato nativo, abilita il graceful shutdown per impostazione predefinita ed estende il supporto ai virtual threads nell'intero framework. > **Prerequisiti** > > Spring Boot 3.4 richiede Java 17 come minimo e supporta Java 21 per i virtual threads. Questa versione utilizza Spring Framework 6.2. ## Logging strutturato nativo Il logging strutturato rappresenta un avanzamento importante per l'osservabilità delle applicazioni. Invece di log testuali difficili da analizzare, Spring Boot 3.4 genera log in formato JSON consumabili da strumenti come Elasticsearch, Grafana Loki o Datadog. Tre formati sono supportati 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 ``` Questa semplice configurazione produce log JSON strutturati in modo automatico. ```java // LoggingController.java @RestController @RequestMapping("/api/demo") public class LoggingController { // Logger injection via SLF4J private static final Logger logger = LoggerFactory.getLogger(LoggingController.class); @GetMapping("/action") public ResponseEntity performAction(@RequestParam String userId) { // Log will be automatically formatted as structured JSON logger.info("Action performed by user: {}", userId); return ResponseEntity.ok("Action completed"); } } ``` Con il formato ECS abilitato, questo log diventa un oggetto JSON contenente timestamp, livello, messaggio, nome della classe, thread e metadati dell'applicazione. Questa struttura semplifica la ricerca e l'aggregazione nelle piattaforme di monitoraggio. ## Graceful Shutdown abilitato per impostazione predefinita Cambiamento importante: il graceful shutdown è ora abilitato per impostazione predefinita. Le richieste HTTP in corso vengono elaborate prima dell'arresto del server, evitando errori 502 durante i deployment. ```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 ``` Questo comportamento si applica a tutti i server embedded: Tomcat, Jetty, Undertow e Reactor Netty. ```java // LifecycleConfig.java @Configuration public class LifecycleConfig { private static final Logger logger = LoggerFactory.getLogger(LifecycleConfig.class); @Bean public ApplicationListener 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. }; } } ``` Questo miglioramento semplifica l'implementazione di deployment senza downtime, senza necessità di configurazione aggiuntiva nella maggior parte dei casi. ## Supporto esteso ai Virtual Threads Spring Boot 3.4 estende il supporto ai virtual threads (Java 21+) a più componenti. `OtlpMeterRegistry` e il server Undertow ora utilizzano virtual threads quando abilitati. ```properties # application.properties # Enable virtual threads globally spring.threads.virtual.enabled=true ``` Questa singola proprietà trasforma il modello di threading dell'applicazione. Ogni richiesta HTTP ottiene il proprio virtual thread, consentendo migliaia di connessioni simultanee senza esaurire il pool di thread. ```java // AsyncService.java @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); } } ``` I virtual threads eccellono nelle applicazioni con carico I/O elevato: chiamate HTTP, query al database, operazioni sui file. Il thread del sistema operativo viene rilasciato durante l'attesa e riassegnato alla ripresa. > **Compatibilità** > > I virtual threads richiedono Java 21 come minimo. Su Java 17, questa proprietà viene ignorata e si applica il comportamento classico. ## RestClient e RestTemplate migliorati Spring Boot 3.4 normalizza la configurazione del client HTTP. La selezione dell'`HttpRequestFactory` segue ora una precedenza chiara basata sul classpath. ```java // HttpClientConfig.java @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(); } } ``` Anche la configurazione del comportamento dei redirect è semplificata. ```properties # application.properties # Force specific implementation spring.http.client.factory=jdk # Configure redirect behavior spring.http.client.redirects=dont-follow ``` Per un controllo più dettagliato, il nuovo `ClientHttpRequestFactoryBuilder` consente una configurazione programmatica completa. ```java // CustomHttpClientConfig.java @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(); } } ``` Questo approccio offre massima flessibilità mantenendo un'API coerente indipendentemente dall'implementazione HTTP sottostante. ## MockMvcTester per test fluenti Spring Boot 3.4 introduce `MockMvcTester`, un'alternativa basata su AssertJ a `MockMvc`. Questo nuovo approccio rende i test più leggibili ed espressivi. ```java // UserControllerTest.java @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"); } } ``` Rispetto all'approccio precedente con `MockMvc`, le asserzioni sono più concise e il concatenamento risulta più naturale. ```java // ComparisonTest.java @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")); } } ``` `MockMvcTester` viene configurato automaticamente quando AssertJ è presente nel classpath (incluso di default con `spring-boot-starter-test`). ## Docker Compose e Testcontainers migliorati Il supporto Docker Compose guadagna flessibilità con file di configurazione multipli e argomenti personalizzati. ```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 ``` I nuovi servizi vengono rilevati e configurati 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 ``` Spring Boot 3.4 rileva automaticamente questi servizi e configura le proprietà di connessione corrispondenti. Per i test con Testcontainers, nuovi container sono supportati. ```java // IntegrationTestConfig.java @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"); } } ``` L'annotazione `@ServiceConnection` configura automaticamente le proprietà di connessione, eliminando la necessità di `@DynamicPropertySource` nella maggior parte dei casi. ## Actuator SSL e osservabilità Il nuovo endpoint `/actuator/info` espone ora informazioni sui certificati SSL configurati: date di validità, emittente e soggetto. ```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 ``` Questa funzionalità consente il monitoraggio della scadenza dei certificati direttamente tramite actuator, facilitando l'automazione dei rinnovi. ```java // SslMonitoringConfig.java @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(); }; } } ``` Per l'osservabilità, il trasporto OTLP ora supporta gRPC oltre a 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 ``` Il gruppo applicazione (`spring.application.group`) consente di raggruppare logicamente più servizi nei dashboard di osservabilità. ## Immagini OCI più leggere Il builder predefinito per le immagini OCI passa da `paketobuildpacks/builder-jammy-base` a `paketobuildpacks/builder-jammy-java-tiny`, producendo immagini significativamente più piccole. ```groovy // build.gradle tasks.named("bootBuildImage") { // Native ARM support (new) imagePlatform = "linux/arm64" // New security flag trustBuilder = false // Image configuration imageName = "myregistry.com/myapp:${version}" } ``` Il nuovo parametro `imagePlatform` semplifica le build multipiattaforma per ARM e x64. ```xml org.springframework.boot spring-boot-maven-plugin linux/arm64 paketobuildpacks/builder-jammy-java-tiny ``` Queste immagini ottimizzate si avviano più velocemente e consumano meno risorse, particolarmente vantaggioso per i deployment su Kubernetes. > **Nota sulla migrazione** > > Il cambio di builder può influenzare applicazioni che dipendono da determinati strumenti di sistema. Si consiglia di testare le nuove immagini prima del deployment in produzione. ## Modifiche alla Bean Validation Spring Boot 3.4 allinea il comportamento della validazione alla specifica Bean Validation. La validazione non si propaga più automaticamente alle proprietà annidate. ```java // ConfigProperties.java @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 } ``` Questa modifica può influenzare le applicazioni esistenti. Si consiglia di verificare le classi `@ConfigurationProperties` e aggiungere `@Valid` dove la validazione deve propagarsi. ## Deprecazione di @MockBean e @SpyBean Le annotazioni `@MockBean` e `@SpyBean` di Spring Boot sono deprecate a favore delle nuove annotazioni Mockito. ```java // UserServiceTest.java (new approach) @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"); } } ``` Le vecchie annotazioni funzionano ancora ma mostrano avvisi di deprecazione. Si consiglia di pianificare la migrazione a `@MockitoBean` e `@MockitoSpyBean`. ## Conclusione Spring Boot 3.4 offre miglioramenti sostanziali in produttività e osservabilità: **Checklist di migrazione:** - Abilitare il logging strutturato per migliorare l'osservabilità - Verificare il comportamento del graceful shutdown (ora abilitato per impostazione predefinita) - Considerare i virtual threads per applicazioni con carico I/O elevato (Java 21+) - Migrare a MockMvcTester per test più leggibili - Aggiungere `@Valid` sulle proprietà `@ConfigurationProperties` annidate - Sostituire `@MockBean`/`@SpyBean` con `@MockitoBean`/`@MockitoSpyBean` - Testare le nuove immagini OCI prima del deployment in produzione Spring Boot 3.4 consolida la sua posizione come framework di riferimento per lo sviluppo Java moderno, con particolare attenzione agli standard di osservabilità e performance. **Fonti:** - [Spring Boot 3.4.0 Release Announcement](https://spring.io/blog/2024/11/21/spring-boot-3-4-0-available-now/) - [Spring Boot 3.4 Release Notes](https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.4-Release-Notes) - [Bootiful Spring Boot 3.4](https://spring.io/blog/2024/11/24/bootiful-34-boot/) --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/it/blog/spring-boot/spring-boot-3-4-new-features