Spring Framework 7 + Jakarta EE 11 위에 서는 Spring Boot의 현재 세대. 4.0이 2025-11, 4.1이 2026-06에 나왔다.
먼저 알아야 할 것 — Spring Boot에는 LTS가 없다
- 마이너 릴리스 — 6개월마다
- 오픈소스 지원 — 각 마이너당 약 12~13개월
- LTS — 존재하지 않음
"LTS를 잡고 몇 년 버틴다"는 전략 자체가 성립하지 않는 정책이라, 올라가지 않는 것이 곧 부채가 된다. (Java의 LTS와 혼동하기 쉬운 지점이다.)
| 버전 | 출시 | OSS 지원 종료 |
|---|---|---|
| 4.1 | 2026-06 | 2027-07 |
| 4.0 | 2025-11 | 2026-12 |
| 3.5 | 2025-05 | 2026-06 (종료) |
베이스라인
Java 17이 그대로 최소 요구 버전이고 Java 25를 1급으로 지원한다. 2.7 → 3.0 때의 javax → jakarta 같은 전면 개명은 없다.
주요 변화
① 모듈화 — 업그레이드에서 실제로 부딪히는 지점
jar가 잘게 쪼개지면서, 예전에 다른 스타터에 묻어 들어오던 자동 설정이 더는 안 딸려온다. 3.x에서 올라오면 "분명히 되던 게 안 되는" 경험을 하는데, 원인은 대개 버그가 아니라 의존성을 명시적으로 선언해야 하는 것이다(spring-boot-starter-flyway 등). --debug나 /actuator/conditions의 조건 평가 리포트가 정확히 어떤 자동 설정이 왜 탈락했는지 알려 준다.
② API 버저닝이 프레임워크 기능이 됐다
@GetMapping(value = "/products/{id}", version = "1")
ProductV1 getV1(@PathVariable Long id) { ... }
@GetMapping(value = "/products/{id}", version = "2") // 같은 경로, 다른 버전
ProductV2 getV2(@PathVariable Long id) { ... }
버전을 헤더·쿼리 파라미터·미디어타입·경로 중 어디서 읽을지는 ApiVersionConfigurer로 설정한다. version = "1.2+" 같은 기준선 표기도 된다.
③ HTTP Service Client — 선언형 REST 클라이언트
public interface PaymentClient {
@PostExchange("/charges")
ChargeResult charge(@RequestBody ChargeRequest req);
}
@SpringBootApplication
@ImportHttpServices(group = "payment", basePackages = "com.example.client")
class App { }
인터페이스만 정의하면 구현을 프레임워크가 만든다. base-url·타임아웃은 spring.http.serviceclient.<group>.* 로 설정한다.
④ JSpecify 널 안전성 — 패키지에 @NullMarked를 걸면 그 안이 기본 non-null이 되고, 널이 될 수 있는 것만 @Nullable로 표시한다. 표준 규격을 채택해 IDE·정적 분석이 함께 읽는다.
⑤ @Retryable·@ConcurrencyLimit 내장 — 지수 백오프·jitter를 포함한 재시도와 동시 실행 제한이 외부 라이브러리 없이 들어왔다.
⑥ Spring Data AOT — 리포지토리 쿼리 생성을 기동 시점이 아니라 컴파일 시점으로 옮겨 기동을 크게 줄이고, 잘못된 쿼리를 빌드에서 잡는다.
4.1에서 더해진 것
- lazy JDBC connection — 트랜잭션 시작이 아니라 첫 SQL 시점에 커넥션을 빌린다. 트랜잭션 안에 외부 API 호출이 섞여 있을 때 커넥션 점유 시간이 짧아진다.
- gRPC 자동 설정,
@RedisListener, 사용자가 준 URL로 내부망을 찌르는 SSRF를 막는InetAddressFilter.
업그레이드 순서
① 3.5 최신 패치까지 올려 deprecation 경고를 0으로 → ② Java 17 이상 확인 → ③ 4.x로 올리며 사라진 암묵적 의존성을 조건 리포트로 채운다. 4.0은 지원 종료가 가까우니 신규는 4.1부터 시작한다.
모듈화가 실제로 어떻게 드러나나
3.x 에서 잘 되던 앱을 4.x 로 올렸더니
Flyway 마이그레이션이 실행되지 않는다 / H2 콘솔이 안 뜬다 / 특정 Actuator 엔드포인트가 없다
↓
버그가 아니라, 다른 스타터에 묻어 오던 자동 설정이 이제 안 딸려오는 것
# 원인을 찾는 표준 절차
java -jar app.jar --debug # 조건 평가 리포트
# 또는 실행 중인 앱에서
curl localhost:8080/actuator/conditions
리포트의 Negative matches에서 @ConditionalOnClass 실패로 찍히면 답은 하나다 — 해당 스타터를 명시적으로 선언한다(spring-boot-starter-flyway 등).