# Spring Boot 3.4: Усі нововведення детально > Spring Boot 3.4 приносить нативне структуроване логування, розширені virtual threads, graceful shutdown за замовчуванням та MockMvcTester. Повний огляд нових можливостей. - 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, випущений у листопаді 2024 року, надає значні покращення в продуктивності розробників та швидкодії додатків. Ця версія впроваджує нативне структуроване логування, активує graceful shutdown за замовчуванням та розширює підтримку virtual threads у всьому фреймворку. > **Передумови** > > Spring Boot 3.4 вимагає мінімум Java 17 та підтримує Java 21 для virtual threads. Ця версія використовує Spring Framework 6.2. ## Нативне структуроване логування Структуроване логування являє собою важливий крок вперед для спостережуваності додатків. Замість текстових логів, які важко аналізувати, Spring Boot 3.4 генерує логи у форматі JSON, придатні для обробки інструментами на кшталт Elasticsearch, Grafana Loki чи Datadog. Три формати підтримуються нативно: Elastic Common Schema (ECS), Logstash та 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 ``` Ця проста конфігурація автоматично генерує форматовані структуровані JSON-логи. ```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"); } } ``` При увімкненому форматі ECS цей лог перетворюється на JSON-об'єкт, що містить timestamp, рівень, повідомлення, назву класу, потік та метадані додатку. Така структура спрощує пошук та агрегацію на платформах моніторингу. ## Graceful Shutdown увімкнений за замовчуванням Важлива зміна: graceful shutdown тепер увімкнений за замовчуванням. Поточні HTTP-запити обробляються перед зупинкою сервера, що запобігає помилкам 502 під час розгортання. ```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 ``` Ця поведінка застосовується до всіх вбудованих серверів: Tomcat, Jetty, Undertow та 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. }; } } ``` Це покращення спрощує реалізацію розгортань без простою, без потреби додаткової конфігурації у більшості випадків. ## Розширена підтримка Virtual Threads Spring Boot 3.4 розширює підтримку virtual threads (Java 21+) на більшу кількість компонентів. `OtlpMeterRegistry` та сервер Undertow тепер використовують virtual threads при їх активації. ```properties # application.properties # Enable virtual threads globally spring.threads.virtual.enabled=true ``` Ця єдина властивість трансформує модель потоків додатку. Кожен HTTP-запит отримує власний virtual 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); } } ``` Virtual threads демонструють найкращі результати у додатках з інтенсивним I/O: HTTP-виклики, запити до баз даних, файлові операції. Потік операційної системи звільняється під час очікування та повторно призначається при відновленні. > **Сумісність** > > Virtual threads вимагають мінімум Java 21. На Java 17 ця властивість ігнорується і застосовується класична поведінка. ## Покращений RestClient та RestTemplate Spring Boot 3.4 нормалізує конфігурацію HTTP-клієнта. Вибір `HttpRequestFactory` тепер дотримується чіткої послідовності на основі 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(); } } ``` Конфігурація поведінки перенаправлень також спрощена. ```properties # application.properties # Force specific implementation spring.http.client.factory=jdk # Configure redirect behavior spring.http.client.redirects=dont-follow ``` Для більш детального контролю новий `ClientHttpRequestFactoryBuilder` дозволяє повну програмну конфігурацію. ```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(); } } ``` Цей підхід забезпечує максимальну гнучкість зі збереженням консистентного API незалежно від базової HTTP-реалізації. ## MockMvcTester для зручного тестування Spring Boot 3.4 представляє `MockMvcTester`, альтернативу `MockMvc` на основі AssertJ. Цей новий підхід робить тести більш читабельними та виразними. ```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"); } } ``` Порівняно з попереднім підходом із `MockMvc`, перевірки стали більш лаконічними, а ланцюжки виглядають природніше. ```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` автоматично налаштовується, коли AssertJ присутній у classpath (за замовчуванням включений у `spring-boot-starter-test`). ## Покращений Docker Compose та Testcontainers Підтримка Docker Compose набуває гнучкості завдяки кільком файлам конфігурації та користувацьким аргументам. ```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 ``` Нові сервіси автоматично виявляються та налаштовуються. ```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 автоматично виявляє ці сервіси та налаштовує відповідні властивості з'єднання. Для тестування з Testcontainers підтримуються нові контейнери. ```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"); } } ``` Анотація `@ServiceConnection` автоматично налаштовує властивості з'єднання, усуваючи потребу в `@DynamicPropertySource` у більшості випадків. ## Actuator SSL та спостережуваність Новий endpoint `/actuator/info` тепер надає інформацію про налаштовані SSL-сертифікати: дати дійсності, видавець та суб'єкт. ```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 ``` Ця функціональність дозволяє моніторити закінчення терміну дії сертифікатів безпосередньо через actuator, полегшуючи автоматизацію оновлення. ```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(); }; } } ``` Для спостережуваності OTLP-транспорт тепер підтримує gRPC на додаток до 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 ``` Група додатків (`spring.application.group`) дозволяє логічно групувати кілька сервісів у дашбордах спостережуваності. ## Легші OCI-образи Стандартний OCI-білдер образів змінюється з `paketobuildpacks/builder-jammy-base` на `paketobuildpacks/builder-jammy-java-tiny`, створюючи значно менші образи. ```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}" } ``` Новий параметр `imagePlatform` спрощує кросплатформну збірку для ARM та x64. ```xml org.springframework.boot spring-boot-maven-plugin linux/arm64 paketobuildpacks/builder-jammy-java-tiny ``` Ці оптимізовані образи запускаються швидше та споживають менше ресурсів, що особливо корисно для розгортань у Kubernetes. > **Примітка щодо міграції** > > Зміна білдера може вплинути на додатки, які залежать від певних системних інструментів. Нові образи слід протестувати перед розгортанням у продакшен. ## Зміни в Bean Validation Spring Boot 3.4 узгоджує поведінку валідації зі специфікацією Bean Validation. Валідація більше не каскадується автоматично до вкладених властивостей. ```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 } ``` Ця зміна може вплинути на існуючі додатки. Слід перевірити класи `@ConfigurationProperties` та додати `@Valid` там, де валідація має каскадуватися. ## Застарівання @MockBean та @SpyBean Анотації `@MockBean` та `@SpyBean` у Spring Boot позначені як застарілі на користь нових анотацій 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"); } } ``` Старі анотації все ще працюють, але показують попередження про застарівання. Варто запланувати міграцію на `@MockitoBean` та `@MockitoSpyBean`. ## Висновок Spring Boot 3.4 надає суттєві покращення в продуктивності та спостережуваності: **Контрольний список міграції:** - Увімкнути структуроване логування для покращення спостережуваності - Перевірити поведінку graceful shutdown (тепер увімкнений за замовчуванням) - Розглянути virtual threads для додатків з інтенсивним I/O (Java 21+) - Мігрувати на MockMvcTester для більш читабельних тестів - Додати `@Valid` на вкладені властивості `@ConfigurationProperties` - Замінити `@MockBean`/`@SpyBean` на `@MockitoBean`/`@MockitoSpyBean` - Протестувати нові OCI-образи перед розгортанням у продакшен Spring Boot 3.4 зміцнює свою позицію як еталонний фреймворк для сучасної Java-розробки, з особливою увагою до стандартів спостережуваності та продуктивності. **Джерела:** - [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/uk/blog/spring-boot/spring-boot-3-4-new-features