Spring Boot 4.0이 2025년 11월 20일 GA(General Availability, 정식 안정 버전) 로 출시되었습니다. Spring Boot 3.5.x 대비 꽤 큰 변화가 있어, 주요 차이점을 용어 설명과 함께 정리했습니다.
릴리즈 & 지원 주기
| Spring Boot 3.5.x | Spring Boot 4.0 | |
|---|---|---|
| 상태 | 안정 버전 | GA (2025.11.20 출시) |
| OSS 지원 종료 | 2026년 6월 | 현재 활성 지원 중 |
⚠️ Spring Boot 3.5.x는 2026년 6월에 지원이 종료됩니다. 프로덕션 서비스라면 마이그레이션 계획을 미리 세워두는 것이 좋습니다.
Java & 플랫폼 기준선
- Java 최소 요구 버전: 17 (3.5와 동일)
- Java 25 first-class 지원 추가 — AOT 컴파일 및 GraalVM 네이티브 이미지가 Java 25 기준으로 테스트됨
- Jakarta EE 기준이 11로 상향 → Hibernate 7.x, Bean Validation 3.1, Tomcat 11 필수
⚠️
javax.*임포트가 아직 남아있다면 전부jakarta.*로 교체해야 합니다.
용어 설명: First-class 지원이란?
“일등 시민 지원"이라는 표현으로, 공식적으로 완전히 지원한다는 뜻입니다.
- ✅ 해당 환경에서 충분히 테스트됨
- ✅ 전용 기능도 적극 활용
- ✅ 문제 발생 시 공식적으로 수정해줌
반대로 “지원은 하지만 first-class는 아니다” = 돌아가긴 하지만 최적화나 보장은 없음.
용어 설명: AOT 컴파일 & GraalVM 네이티브 이미지란?
일반적인 Java 실행 방식 (JIT)
소스코드 → .class 파일 → JVM이 실행 중에 번역 → 실행
앱을 실행할 때 JVM이 코드를 분석하고 최적화하므로 시작이 느립니다.
AOT (Ahead-Of-Time) 컴파일
소스코드 → 미리 다 번역해둠 → 실행
실행 전에 미리 다 번역해두므로 시작이 빠릅니다.
GraalVM 네이티브 이미지는 AOT를 극단적으로 적용한 것으로, Java 앱을 JVM 없이 바로 실행 가능한 단독 실행 파일로 만들어 줍니다.
결과: 시작 시간 최대 3배 빠름, 메모리 약 40% 절감. 특히 컨테이너/서버리스 환경에서 유리합니다.
모듈화 (가장 큰 구조적 변화)
Spring Boot 3.5에서 단일 spring-boot-autoconfigure JAR 크기가 2MiB까지 커졌습니다.
Spring Boot 4는 전체 코드베이스를 70개 이상의 작은 JAR로 모듈화했습니다.
필요한 스타터만 골라 쓸 수 있어 의존성 크기 및 CVE 노출 면적이 줄어듭니다.
용어 설명: MiB란?
흔히 아는 MB(메가바이트)와 거의 같은 단위인데, 정확한 기준이 다릅니다.
| 단위 | 기준 | 크기 |
|---|---|---|
| MB (메가바이트) | 1MB = 1,000,000 bytes | 10진법 기준 |
| MiB (메비바이트) | 1MiB = 1,048,576 bytes | 2진법 기준 |
차이는 약 4.8% 정도라 실용적으로는 거의 같다고 봐도 무방합니다.
용어 설명: CVE 노출 면적이란?
CVE (Common Vulnerabilities and Exposures) 는 공개된 보안 취약점에 붙는 번호입니다. 노출 면적(Attack Surface) 은 해킹당할 수 있는 가능성이 있는 코드/의존성의 범위를 말합니다.
- 의존성(라이브러리)이 많을수록 → 취약점 포함 확률 ↑
- 필요한 것만 쓰면 → 취약점에 노출될 가능성 ↓
Spring Boot 4가 70개 모듈로 쪼개져서 필요한 것만 가져다 쓸 수 있게 된 것이 바로 이 CVE 노출 면적을 줄이는 효과입니다.
주요 의존성 업그레이드
| 라이브러리 | 3.5.x | 4.0 |
|---|---|---|
| Jackson | 2.x | 3.x (Breaking Change) |
| JUnit | 5 | 6 |
| Hibernate | 6.x | 7.x |
| Tomcat | 10 | 11 |
| Jakarta EE | 10 | 11 |
Jackson 3.x로의 업그레이드는 Breaking Change입니다. 어노테이션 제거, 더 엄격한 타입 처리, ObjectMapper 동작 변경이 포함되어 커스텀 직렬화 로직에 영향을 줍니다.
기존 spring.jackson.* 설정 키는 spring.jackson2.*로 이동했습니다.
제거된 API들 (Breaking Changes)
3.5까지 deprecated(사용 중단 예고)로 살아남은 API는 4.0에서 예외 없이 모두 제거되었습니다.
주요 제거 목록:
@MockBean/@SpyBean— 3.4에서 deprecated → 4.0에서 제거 (대체제는 3.5에서 도입)WebSecurityConfigurerAdapter— 레거시 보안 설정- Actuator, Security, Web, Data, Messaging 전반의 deprecated 설정 키들
- 레거시 MVC/WebFlux API
Null Safety — JSpecify 도입
Spring Boot 4는 Google 주도의 JSpecify 표준 nullability 어노테이션을 전체 코드베이스에 적용했습니다.
// package-info.java
@NullMarked
package com.example.myapp;
패키지를 @NullMarked로 선언하면 해당 패키지 내 모든 타입은 기본적으로 non-null이 되고,
null이 가능한 경우에만 @Nullable을 표기하는 방식입니다.
기존 org.springframework.lang 어노테이션은 deprecated됩니다.
관측성(Observability) 강화
- Micrometer 2 + Actuator 4: 메트릭, 로그, 트레이스를 최소 설정으로 통합 관리
- Kubernetes 기본 내장 지원: probes, ConfigMaps, Secrets 별도 커스텀 설정 없이 사용 가능
성능 — Virtual Threads
용어 설명: Virtual Threads(가상 스레드)란?
스레드(Thread) 는 프로그램이 동시에 여러 작업을 처리하는 단위입니다. 웹 서버라면 사용자 요청 하나당 스레드 하나가 처리한다고 보면 됩니다.
기존 방식 (OS 스레드)
- 스레드 하나 = OS가 직접 관리하는 진짜 스레드
- 메모리를 많이 차지함 (스레드 하나당 약 1MB)
- 생성/전환 비용이 비쌈
- 수백 개 수준이 한계
요청 1000개 동시에 들어오면?
→ 스레드 1000개 필요 → 메모리 부족 → 서버 다운 위기 😱
Virtual Threads (Java 21 도입)
- JVM이 직접 관리하는 초경량 스레드
- 메모리를 거의 안 차지함
- 수십만 개도 거뜬히 생성 가능
요청 100,000개 동시에 들어와도?
→ Virtual Thread 100,000개 생성 → 문제없음 😎
핵심 장점은 기존 코드를 리액티브(WebFlux 등)로 복잡하게 바꾸지 않아도 높은 동시성을 달성할 수 있다는 점입니다.
# application.yml — 설정 한 줄로 활성화
spring:
threads:
virtual:
enabled: true
실제 사례: Java 17에서는 성능 개선이 거의 없었으나, Java 21로 올리고 Virtual Threads를 활성화했을 때 동일 하드웨어에서 2배의 처리량을 달성했다는 보고가 있습니다.
마이그레이션 권고 사항
마이그레이션 전 체크리스트:
- 먼저 최신 3.5.x로 업그레이드 — deprecated 메서드 경고를 미리 확인
- deprecated API 정리 — 4.0에서 모두 제거되므로 미리 교체
javax.*→jakarta.*전환 완료 확인- Jackson 커스텀 직렬화 로직 점검 — Jackson 3.x는 Breaking Change
@MockBean/@SpyBean대체 — 3.5에서 도입된 대체제로 교체- Java 버전 확인 — 최소 17, 성능을 위해 21 이상 권장
한 줄 요약
Spring Boot 4.0은 모듈화, Jackson 3, JUnit 6, Jakarta EE 11, JSpecify null safety가 핵심 변경점이며, Virtual Threads + Java 21/25 조합에서 성능 이점이 극대화됩니다.