# Spring Boot 3.4: 모든 새로운 기능 상세 설명 > Spring Boot 3.4는 네이티브 구조화 로깅, 확장된 가상 스레드, 기본 그레이스풀 셧다운, 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년 11월에 출시되어 개발자 생산성과 애플리케이션 성능에서 상당한 개선을 제공합니다. 이 버전은 네이티브 구조화 로깅을 도입하고, 그레이스풀 셧다운을 기본으로 활성화하며, 프레임워크 전반에 걸쳐 가상 스레드 지원을 확장합니다. > **전제 조건** > > Spring Boot 3.4는 최소 Java 17이 필요하며, 가상 스레드를 위해 Java 21을 지원합니다. 이 버전은 Spring Framework 6.2를 사용합니다. ## 네이티브 구조화 로깅 구조화 로깅은 애플리케이션 관측성에서 중요한 진전을 나타냅니다. 파싱하기 어려운 텍스트 기반 로그 대신, Spring Boot 3.4는 Elasticsearch, Grafana Loki, Datadog 같은 도구에서 사용할 수 있는 JSON 형식의 로그를 생성합니다. 세 가지 형식이 네이티브로 지원됩니다: 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 객체가 됩니다. 이 구조는 모니터링 플랫폼에서의 검색과 집계를 단순화합니다. ## 기본으로 활성화된 그레이스풀 셧다운 중요한 변경: 그레이스풀 셧다운이 이제 기본으로 활성화됩니다. 진행 중인 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. }; } } ``` 이 개선으로 대부분의 경우 추가 설정 없이 무중단 배포 구현이 간소화됩니다. ## 확장된 가상 스레드 지원 Spring Boot 3.4는 가상 스레드 지원(Java 21+)을 더 많은 컴포넌트로 확장합니다. `OtlpMeterRegistry`와 Undertow 서버가 활성화 시 가상 스레드를 사용합니다. ```properties # application.properties # Enable virtual threads globally spring.threads.virtual.enabled=true ``` 이 단일 속성으로 애플리케이션의 스레딩 모델이 변환됩니다. 각 HTTP 요청이 자체 가상 스레드를 받아 스레드 풀을 고갈시키지 않고 수천 개의 동시 연결이 가능해집니다. ```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/O 집약적인 애플리케이션에서 빛을 발합니다: HTTP 호출, 데이터베이스 쿼리, 파일 작업. OS 스레드는 대기 시간 동안 해제되고 재개 시 재할당됩니다. > **호환성** > > 가상 스레드는 최소 Java 21이 필요합니다. Java 17에서는 이 속성이 무시되고 기존 동작이 적용됩니다. ## 개선된 RestClient와 RestTemplate Spring Boot 3.4는 HTTP 클라이언트 설정을 표준화합니다. `HttpRequestFactory` 선택이 이제 클래스패스 기반의 명확한 우선순위를 따릅니다. ```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(); } } ``` 이 접근 방식은 기본 HTTP 구현과 관계없이 일관된 API로 최대한의 유연성을 제공합니다. ## 유창한 테스트를 위한 MockMvcTester Spring Boot 3.4는 `MockMvc`의 AssertJ 기반 대안인 `MockMvcTester`를 도입합니다. 이 새로운 접근 방식은 테스트를 더 읽기 쉽고 표현력 있게 만듭니다. ```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가 있을 때 자동 설정됩니다(`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과 관측성 새로운 `/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 전송이 이제 HTTP 외에 gRPC를 지원합니다. ```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 지원 중단 Spring Boot의 `@MockBean`과 `@SpyBean` 어노테이션이 새로운 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는 생산성과 관측성에서 상당한 개선을 제공합니다: **마이그레이션 체크리스트:** - 더 나은 관측성을 위해 구조화 로깅 활성화 - 그레이스풀 셧다운 동작 확인 (이제 기본 활성화) - I/O 집약적 애플리케이션에 가상 스레드 고려 (Java 21+) - 더 읽기 쉬운 테스트를 위해 MockMvcTester로 마이그레이션 - 중첩된 `@ConfigurationProperties` 속성에 `@Valid` 추가 - `@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/ko/blog/spring-boot/spring-boot-3-4-new-features