| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | ||
| 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 | 17 | 18 | 19 |
| 20 | 21 | 22 | 23 | 24 | 25 | 26 |
| 27 | 28 | 29 | 30 |
- restapi
- 근로기준법
- 코딩
- SWEA
- 마이라이트
- js
- jpa
- 성인학습지
- 코테
- springboot
- SpringBoot4
- javascript
- java
- 일본어독학
- 에러해결
- 코딩테스트
- 자바
- 마이그레이션
- 가벼운학습지
- React Native
- 백엔드
- 알고리즘
- 자바스크립트
- 프로그래머스
- 삼성
- 생활정보
- 일본어학습지
- spring
- 일본어공부
- 가벼운학습지후기
- Today
- Total
개발에 AtoZ까지
[Spring Boot] 3의 무료 지원이 6월에 끝났습니다 — 4.0과 4.1 중 어디로 올릴까 본문
사내 보안 스캔 결과나 Dependabot PR을 받아 보고 이런 상황에 놓인 분들이 있을 겁니다. "우리 아직 3.5인데, 이거 지금 올려야 하는 건가?"
저는 이 질문을 미루기 좋은 질문이라고 생각했습니다. 3.5가 나온 게 얼마 안 된 것 같았으니까요. 그런데 지원 표를 다시 열어 보니 사정이 달라져 있었습니다. Spring Boot 3.5의 무료 지원은 2026년 6월에 이미 끝났습니다.
이 글을 다 읽으면 세 가지가 정리됩니다. 첫째, 우리 프로젝트가 지금 지원받는 상태인지 아닌지 표에서 직접 읽을 수 있습니다. 둘째, 4.0으로 갈지 4.1로 갈지 고를 기준이 생깁니다. 셋째, 올리는 순간 무엇이 깨지는지 미리 알고 갈 수 있습니다.
미리 밝혀 둘 것이 있습니다. 이 글은 제가 운영 서비스를 4.x로 옮긴 경험담이 아니라, Spring 공식 릴리스 노트와 마이그레이션 가이드를 읽고 정리한 내용입니다(확인일 2026-08-23). 그래서 "우리 코드에서는 이게 터졌다" 같은 얘기 대신, 공식 문서가 명시한 변경점과 그 판단 기준을 옮겼습니다.

브랜치별 무료(OSS) 지원 종료 시점과 오늘의 위치 — 3.4는 2025년 12월, 3.5는 2026년 6월에 이미 끝났습니다
3.5.16이 마지막이었습니다
2026년 6월 25일에 나온 Spring Boot 3.5.16 릴리스 공지에는 이런 문장이 붙어 있습니다.
"End of OSS Support — This is the last OSS release of the 3.5.x generation. To continue to receive OSS support, upgrade to 4.0.x or 4.1.x at your earliest convenience."
풀어 쓰면 이렇습니다. 3.5.x 계열의 무료 릴리스는 이게 끝이고, 계속 무료 지원을 받으려면 가능한 한 빨리 4.0.x나 4.1.x로 올리라는 뜻입니다. 3.5가 Spring Boot 3의 마지막 마이너 버전이었으니, 이 문장은 곧 3 세대 전체의 무료 지원 종료를 뜻합니다.
그래서 지금 3.x를 쓰고 있다면, 새로 발견되는 보안 취약점에 대해 무료 패치가 더 나오지 않는 상태입니다. 이게 "언젠가 올리자"에서 "이번 분기에 계획을 잡자"로 바뀌어야 하는 이유죠.
그런데 3.5는 2032년까지 지원한다고 봤는데요
여기서 많이 헷갈립니다. spring.io 지원 표를 보면 3.5.x 행에 2032-06이라는 숫자가 분명히 적혀 있습니다. 이것만 보면 6년이나 남은 것처럼 보입니다.
표에는 열이 두 개 있습니다. 같은 페이지의 범례가 각각을 이렇게 정의합니다.
| 열 | 뜻 |
|---|---|
| End of OSS Support | 커뮤니티가 제공하는 무료 보안 업데이트·버그픽스가 끝나는 시점 |
| End Enterprise Support | Spring 전문가의 유료 지원이 끝나는 시점(무료 종료 이후의 연장 지원 포함) |
즉 3.5.x의 2032-06은 돈을 내는 상용 지원의 종료일입니다. 무료 쪽은 2026-06에서 이미 끝났습니다. 각 메이저의 마지막 마이너 버전에만 5년 연장 지원이 붙기 때문에 3.5에 유독 긴 숫자가 적혀 있는 겁니다.
정리하면 이렇습니다. 상용 지원 계약이 있는 팀이라면 3.5에 더 머물 수 있습니다. 그렇지 않은 대부분의 팀에게 3.5는 이미 지원이 끝난 버전입니다.

spring.io 프로젝트 페이지의 Spring Boot 지원 표 — OSS 열과 Enterprise 열이 따로 있습니다 (확인일 2026-08-23)
4.0으로 갈까요, 4.1로 갈까요
2026년 8월 23일 기준으로 두 브랜치가 살아 있습니다. 최신 GA는 4.1.1이고, 4.0 계열은 4.0.8까지 나와 있습니다. 4.2는 아직 4.2.0-M1 마일스톤 단계라 후보가 아닙니다.
무료 지원 종료 시점이 갈립니다.
| 브랜치 | 첫 릴리스 | 무료 지원 종료 | 상용 지원 종료 |
|---|---|---|---|
| 4.1.x | 2026-06 | 2027-07 | 2028-07 |
| 4.0.x | 2025-11 | 2026-12 | 2027-12 |
4.0으로 올리면 넉 달 뒤에 또 올려야 합니다. 그래서 지금 시작하는 업그레이드라면 4.1이 기본값입니다.
4.0을 고를 이유가 아예 없는 건 아닙니다. 4.1은 4.0에서 deprecated로 표시했던 것들을 다시 제거했기 때문에, 4.0 → 4.1도 공짜 점프가 아닙니다. 예를 들어 jOOQ가 3.20으로 올라가면서 Java 21 이상을 요구하게 됐습니다. 그래서 Java 17에 묶여 있고 jOOQ를 쓰는 팀은 일단 4.0에 착지한 뒤 자바를 올리는 순서가 나을 수 있습니다.
올리기 전에 우리 환경부터 확인해야 합니다
가장 자주 보이는 오해를 먼저 정리하겠습니다. Spring Boot 4는 Java 21을 요구하지 않습니다. 마이그레이션 가이드의 문장은 이렇습니다.
"Spring Boot 4.0 requires Java 17 or later. Using the latest LTS release of Java is encouraged."
최소는 여전히 17이고, 최신 LTS를 쓰는 게 권장된다는 정도입니다. 4.1.1 문서는 호환 범위를 Java 17 이상 26 이하로 적고 있습니다.
정작 걸리는 쪽은 자바가 아니라 서블릿과 빌드 도구입니다. 4.1.1 기준 요구사항을 옮기면 이렇습니다.
| 항목 | 요구 버전 |
|---|---|
| Java | 17 이상 (26까지 호환) |
| Spring Framework | 7.0.9 이상 |
| Jakarta EE | 11 (Servlet 6.1 베이스라인) |
| Maven | 3.6.3 이상 |
| Gradle | 8.14 이상의 8.x, 또는 9.x |
| 내장 서블릿 컨테이너 | Tomcat 11.0.x, Jetty 12.1.x |
| Kotlin (사용 시) | 2.2 이상 |
| GraalVM native-image (사용 시) | 25 이상 |
여기서 두 줄이 실제로 사람을 막습니다.
Gradle 8.14 미만은 안 됩니다. 8.x라서 괜찮을 거라고 생각하기 쉬운데, 8.13에서는 빌드가 되지 않습니다. ./gradlew --version부터 확인하시는 게 빠릅니다.
Undertow는 못 씁니다. Servlet 6.1을 아직 만족하지 못해서 Undertow 스타터와 내장 서버 사용이 모두 제거됐습니다. Undertow를 쓰고 있다면 이 업그레이드는 서버 교체를 포함하는 작업이 됩니다. 다만 배포 대상 컨테이너 자체는 Tomcat·Jetty만 되는 게 아니라, 문서가 "any Servlet 6.1+ compatible container"라고 열어 두고 있습니다. 내장으로 지원하는 목록이 둘일 뿐이죠.
실제로 무엇이 깨지나요
공식 마이그레이션 가이드에서 영향이 큰 순서로 다섯 가지를 골랐습니다.
1. Jackson 3으로 바뀌었습니다. 기본 JSON 라이브러리가 Jackson 3이 되면서 그룹ID와 패키지가 com.fasterxml.jackson에서 tools.jackson으로 바뀌었습니다(jackson-annotations는 예외입니다). 직접 ObjectMapper를 import해 쓰던 코드는 전부 손을 봐야 합니다.
2. 코드베이스가 모듈로 쪼개졌습니다. 예전에는 서드파티 의존성만 넣으면 자동 설정이 붙던 기능들이, 이제 전용 스타터를 요구합니다. Flyway와 Liquibase가 대표적입니다.
// Spring Boot 3 시절
implementation 'org.flywaydb:flyway-core'
// Spring Boot 4
implementation 'org.springframework.boot:spring-boot-starter-flyway'
3. 테스트가 조용히 깨집니다. @SpringBootTest만으로는 MockMvc, WebClient, TestRestTemplate이 더 이상 주입되지 않습니다. 각각 @AutoConfigureMockMvc, @AutoConfigureTestRestTemplate을 붙여야 합니다.
4. @MockBean과 @SpyBean이 사라졌습니다. 완전히 제거되어 @MockitoBean, @MockitoSpyBean으로 바꿔야 합니다. 테스트가 많은 프로젝트라면 이 치환이 가장 많은 파일을 건드립니다.
5. 3.x에서 deprecated였던 것이 전부 제거됐습니다. 그래서 순서가 중요합니다. 3.x에서 경고를 켜 놓고 deprecated 호출을 먼저 걷어내면, 4.0에서 마주칠 컴파일 에러의 절반이 미리 사라집니다.
이 밖에도 spring-boot-starter-aop가 spring-boot-starter-aspectj로 이름이 바뀌었고, 실행 가능한 jar를 만들던 launch script 기능이 제거됐고, DevTools의 LiveReload가 기본 비활성으로 바뀌었습니다. Spring Framework 7 쪽에서는 HttpHeaders가 더 이상 MultiValueMap을 상속하지 않고, javax.annotation·javax.inject 애노테이션 지원이 완전히 사라졌습니다.

Spring Boot 4.0 마이그레이션 가이드에서 이번 릴리스에 제거된 기능을 설명하는 부분 (확인일 2026-08-23)
공식 절차는 한 번에 뛰지 않습니다
가이드가 권하는 순서는 2단계입니다.
- 먼저 3.5의 최신 패치(3.5.16)로 올린다.
- 그 상태에서 4.0 또는 4.1로 간다.
3.5.16까지 올려 두면 4.0에서 제거될 것들이 3.5에서 deprecated 경고로 먼저 보입니다. 컴파일 경고를 지도로 쓰는 방식이죠.
여기에 완충 장치가 두 개 더 있습니다.
모듈화가 부담스러우면 spring-boot-starter-classic을 넣습니다. 예전처럼 인프라 관련 의존성이 한 번에 클래스패스에 올라오는 중간 상태를 만들어 줍니다(테스트 쪽은 spring-boot-starter-test-classic). 일단 뜨게 만들고 나중에 필요한 스타터만 골라 내는 순서로 갈 수 있습니다.
설정 프로퍼티 이름이 바뀐 걸 찾으려면 마이그레이터를 씁니다.
runtimeOnly 'org.springframework.boot:spring-boot-properties-migrator'
이걸 넣고 애플리케이션을 띄우면 시작 로그에 바뀐 프로퍼티 진단이 출력됩니다. 마이그레이션이 끝나면 반드시 다시 제거해야 합니다.
Jackson 2를 당장 못 버리는 경우에도 spring-boot-jackson2 모듈이 있습니다. 다만 이건 처음부터 deprecated 상태로 배포됐고 이후 릴리스에서 제거될 예정이라, 임시 다리로만 쓰는 게 맞습니다. 참고로 Jersey 4.0은 Jackson 3을 지원하지 않아서, Jersey로 JSON을 다루는 프로젝트는 이 모듈이 선택이 아니라 필수가 됩니다.

권장 경로와 완충 장치 — 3.5.16을 거쳐 4.1로 가면서 classic 스타터와 properties-migrator로 충격을 나눕니다
Spring Boot만 올라가는 게 아닙니다
이 부분을 놓치면 업그레이드 일정이 두 배로 늘어납니다. Spring Boot 4는 포트폴리오 전체의 메이저 업그레이드를 끌고 옵니다. 가이드는 사용 중인 프로젝트의 릴리스 노트를 각각 확인하라고 명시합니다.
- Spring Security 7.0
- Spring Data 2025.1
- Spring Batch 6.0
- Spring Integration 7.0
- Spring for Apache Kafka 4.0
Spring Cloud를 쓴다면 릴리스 트레인 버전도 맞춰야 합니다. 2025.1.x(Oakwood)가 Boot 4.0.x를 지원하고, 2025.1.2부터 4.1.x도 지원합니다. 현재 버전은 2025.1.3입니다.
MyBatis처럼 Spring이 관리하지 않는 라이브러리도 확인이 필요합니다. 다행히 mybatis-spring-boot-starter는 4.0부터 Boot 4.0+를 지원하고, 4.1.0이 2026년 7월 16일에 나와 있습니다.
Spring Boot가 버전을 관리하지 않는 의존성은 프로젝트가 직접 버전을 박아 두는데, 이런 것들이 업그레이드 후에 조용히 런타임에서 터집니다. 올리기 전에 목록을 한 번 훑어 두시면 좋습니다.
지금 올릴 팀과 조금 기다릴 팀
민수 씨 팀을 예로 들어 보겠습니다. Spring Boot 3.5.9, Java 17, Gradle 8.10, Tomcat 내장, Flyway를 쓰고 테스트에 @MockBean이 40군데 있는 프로젝트입니다.
이 팀이 할 일은 순서가 이렇게 나옵니다. Gradle을 8.14 이상으로 올리고, 3.5.16으로 먼저 올려 deprecated 경고를 정리하고, @MockBean을 @MockitoBean으로 일괄 치환하고, Flyway 스타터로 바꾸고, 4.1로 올립니다. Undertow를 쓰지 않으니 가장 큰 지뢰는 피한 경우죠.
일반화하면 이렇게 갈립니다.
지금 올리는 게 맞는 경우
- 무료 보안 패치가 필요한 서비스(=대부분의 팀)
- 내장 서버가 Tomcat이나 Jetty인 경우
- Spring Cloud를 안 쓰거나 2025.1.2 이상으로 올릴 수 있는 경우
분기를 나눠 준비할 경우
- Undertow를 쓰고 있어서 서버 교체가 선행되는 경우
- Jersey로 JSON을 처리하는 경우
- Java 17에 묶여 있고 jOOQ를 쓰는 경우(4.0에 먼저 착지)
- Kotlin을 쓰거나 빌드에 null checker를 두는 경우 — null 안전성 표기가 JSR 305에서 JSpecify로 바뀌면서 타입 nullness 변경으로 컴파일이 깨질 수 있습니다
하지 말아야 할 것
- 라이브러리나 자체 스타터를 배포하는 팀이 하나의 아티팩트로 Boot 3과 4를 동시 지원하려는 시도. 가이드가 모듈화 때문에 강하게 비권장합니다. 브랜치를 나누는 편이 낫습니다.
- 3.5에 머물면서 "상용 지원이 2032년까지니까 괜찮다"고 판단하는 것. 계약이 없다면 그 숫자는 우리 얘기가 아닙니다.
올리기 전 확인 목록
[ ] ./gradlew --version → 8.14 이상인가 (또는 Maven 3.6.3 이상)
[ ] 내장 서버가 Undertow인가 → 그렇다면 서버 교체가 선행 작업
[ ] Java 17 이상인가 (21은 필수 아님, jOOQ 쓰면 21 필요)
[ ] 3.5.16으로 먼저 올리고 deprecated 경고를 0으로 만들었는가
[ ] @MockBean·@SpyBean 사용처를 모두 찾았는가
[ ] com.fasterxml.jackson 직접 import 사용처를 모두 찾았는가
[ ] Flyway·Liquibase 등을 전용 스타터로 바꿨는가
[ ] @SpringBootTest에서 MockMvc·TestRestTemplate 쓰는 테스트에 @AutoConfigure~를 붙였는가
[ ] Spring Cloud·Security·Data·Batch 버전 호환표를 확인했는가
[ ] properties-migrator로 프로퍼티 변경을 확인하고, 끝난 뒤 제거했는가
치환 대상을 먼저 세어 보면 작업량 감이 잡힙니다.
# 제거된 애노테이션 사용처
grep -rn "@MockBean\|@SpyBean" src/test --include=*.java | wc -l
# Jackson 패키지 직접 참조
grep -rn "com.fasterxml.jackson" src --include=*.java | wc -l
# 4.0에서 사라질 deprecated 호출 (3.5.16에서 먼저 확인)
./gradlew compileJava -Werror
다음에 볼 글
업그레이드하면서 함께 정리하기 좋은 게 HTTP 클라이언트입니다. RestTemplate이 Spring Framework 7 문서에서 deprecated로 선언됐는데, 이게 실제로 어떤 상태이고 언제까지 쓸 수 있는지는 따로 볼 만한 주제라 다음 글에서 다루겠습니다. 요청·응답 처리 자체가 헷갈린다면 전송 방식에 따라 파라미터 받는 방법과 HTTP 상태 코드 제어를 먼저 보시면 순서가 잡힙니다. 테스트 쪽을 손볼 계획이라면 테스트 슬라이스 고르는 기준도 같이 보시면 좋습니다.
버전과 지원 종료 시점은 자주 바뀝니다. 이 글의 숫자는 모두 2026년 8월 23일에 공식 페이지에서 확인한 값이니, 실제 작업 전에 spring.io 지원 표와 마이그레이션 가이드를 본인 대상 버전으로 한 번 더 확인해 주세요. 잘못된 내용이나 보충이 필요한 부분이 있으면 댓글로 알려 주시면 반영하겠습니다.
참고한 자료
- Spring Blog — Spring Boot 3.5.16 available now, 3.5.x 마지막 OSS 릴리스 공지 (확인일 2026-08-23)
- spring.io — Spring Boot 프로젝트 페이지의 Support 표와 범례, 브랜치별 OSS·Enterprise 종료 시점 (확인일 2026-08-23)
- GitHub Wiki — Spring Boot 4.0 Migration Guide, 베이스라인·제거 기능·마이그레이션 전략 (확인일 2026-08-23)
- GitHub Wiki — Spring Boot 4.1 Release Notes, 4.0 대비 제거 항목과 jOOQ 3.20 (확인일 2026-08-23)
- GitHub Wiki — Spring Framework 7.0 Release Notes, 베이스라인 상향과 제거·deprecated 목록 (확인일 2026-08-23)
- docs.spring.io — Spring Boot System Requirements, 4.1.1 기준 Java·빌드도구·서블릿 컨테이너 요구사항 (확인일 2026-08-23)
- spring.io — Spring Cloud 프로젝트 페이지의 릴리스 트레인 호환 표 (확인일 2026-08-23)
- mybatis.org — MyBatis-Spring-Boot-Starter 요구사항 표 (확인일 2026-08-23)
'백엔드 > Spring' 카테고리의 다른 글
| [MySQL] 8.0을 그냥 두면 RDS 요금이 붙습니다 — 8.4와 9.7 사이에서 고르기 (0) | 2026.09.02 |
|---|---|
| [Spring] Security 7로 올리면 컴파일부터 깨집니다 — 6.x에서 미리 지울 코드 (0) | 2026.09.01 |
| [Spring] JPA냐 MyBatis냐, 2026년에 다시 고르기 — 근거 다섯 가지가 이미 옛말입니다 (0) | 2026.08.28 |
| [Spring Boot] @SpringBootTest를 언제 쓰고 언제 쓰지 말까 — 테스트 슬라이스 고르는 기준 (0) | 2026.08.22 |
| [MySQL] 트랜잭션 격리수준 — REPEATABLE READ인데 왜 값이 어긋날까요 (0) | 2026.08.21 |
| [MySQL] 인덱스를 만들었는데 안 타는 5가지 경우 — EXPLAIN 한 줄로 확인합니다 (0) | 2026.08.20 |
| docker-compose 명령이 안 먹는다면 — Compose V2 전환과 Spring Boot가 대신 띄워 주는 컨테이너 (0) | 2026.08.15 |