![[Spring Boot] 3.x 마이그레이션 설치방법 - 실무에서 겪는 문제와 해결법 대표 이미지](https://blog.kakaocdn.net/dna/biN4gU/dJMcahcKv5m/AAAAAAAAAAAAAAAAAAAAAJfxpQiPmb0Upgx2nIY996dvbh5pfzemuAtipwRZuzeh/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&expires=1774969199&allow_ip=&allow_referer=&signature=N210d%2FcSHjzEbMVtGarXwsU5NZ0%3D)
안녕하세요!
재아군의 관찰인생입니다.
오늘은 많은 자바 개발자분들이 고민하고 계실 Spring Boot 3.x 마이그레이션에 대해 이야기해보려 합니다.
Spring Boot 2.x에서 3.x로의 전환은 단순한 버전 업그레이드가 아닙니다.
Java 17 필수 채택, Jakarta EE 네임스페이스 변경, 그리고 수많은 의존성 변화까지 — 실무에서 마이그레이션을 진행하면서 만나게 되는 다양한 문제들과 그 해결법을 상세히 다뤄보겠습니다.
![[Spring Boot] 3.x 마이그레이션 설치방법 - 실무에서 겪는 문제와 해결법 개요 다이어그램](https://blog.kakaocdn.net/dna/dO6wA2/dJMcagx74vO/AAAAAAAAAAAAAAAAAAAAAGXmCgBfLjn8G69Uk0_WLXyAsiNdyhmOQ49xG2LDsLCe/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&expires=1774969199&allow_ip=&allow_referer=&signature=2KeRbHE%2FzvOvjTHlgFj0evAwZiE%3D)
![[Spring Boot] 3.x 마이그레이션 설치방법 - 실무에서 겪는 문제와 해결법 핵심 포인트](https://blog.kakaocdn.net/dna/bbT04r/dJMcadOTVk2/AAAAAAAAAAAAAAAAAAAAAIoH6eTz4kq297cIgDdl_TVCOVxlGltxHPFfqfCEuTKU/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&expires=1774969199&allow_ip=&allow_referer=&signature=geegXxuQ98JhMJmGdlV6M%2BwT5q8%3D)
1. Spring Boot 3.x란 무엇인가?
Spring Boot 3.x는 2022년 11월에 정식 출시된 Spring Boot의 메이저 버전입니다.
Spring Framework 6을 기반으로 하며, Java 17을 최소 요구 버전으로 채택한 것이 가장 큰 변화입니다.
기존 Java EE에서 Jakarta EE로의 전환이 이루어졌고, 이는 패키지 네임스페이스가 javax.에서 jakarta.로 변경되었음을 의미합니다.
왜 3.x 마이그레이션이 필요한가?
Spring Boot 2.x 시리즈는 2023년 11월부로 공식 OSS 지원이 종료되었습니다.
이는 보안 패치와 버그 수정이 더 이상 제공되지 않음을 뜻하며, 프로덕션 환경에서 2.x를 계속 사용하는 것은 보안 리스크를 감수하는 것과 같습니다.
기존 환경에서의 문제점 4가지
- 보안 취약점 미패치: Spring Boot 2.x의 CVE가 발견되어도 공식 수정이 제공되지 않습니다. 예를 들어 Spring Security의 인증 우회 취약점 같은 치명적인 이슈가 발생해도 직접 패치해야 합니다.
- GraalVM 네이티브 이미지 미지원: Spring Boot 2.x는 GraalVM 네이티브 컴파일을 공식 지원하지 않습니다. 클라우드 환경에서 콜드 스타트 시간을 줄이기 위해 네이티브 이미지가 필수적인데, 이를 활용할 수 없습니다.
- 최신 Java 기능 활용 불가: Virtual Thread(Java 21), Record 패턴 매칭(Java 21), Sealed Class(Java 17) 등 최신 JDK 기능과의 통합이 2.x에서는 제한적입니다.
- 라이브러리 호환성 한계: 주요 서드파티 라이브러리들이 Jakarta EE 기반으로 전환하면서, Spring Boot 2.x와의 호환성을 점차 중단하고 있습니다. Hibernate 6.x, Tomcat 10.x 등이 대표적입니다.
![[Spring Boot] 3.x 마이그레이션 설치방법 - 실무에서 겪는 문제와 해결법 프로세스 흐름](https://blog.kakaocdn.net/dna/bWTRlF/dJMcag5ZM8O/AAAAAAAAAAAAAAAAAAAAAJaMdWK5ATdd_ULYqCuomW4oLfPhGdpcIXXLr1EfrfEW/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&expires=1774969199&allow_ip=&allow_referer=&signature=YdNqP5aako9mzxhbpRLDWjVV14c%3D)
![[Spring Boot] 3.x 마이그레이션 설치방법 - 실무에서 겪는 문제와 해결법 비교 테이블](https://blog.kakaocdn.net/dna/b0DUNS/dJMcacCw3aa/AAAAAAAAAAAAAAAAAAAAALc8NfXWkeI-7Z3E0fYXz5-hlPRO0DkEBBGYg8rdGmvZ/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&expires=1774969199&allow_ip=&allow_referer=&signature=fsH3mmOd62ela9%2BNmoyjEPFGOv0%3D)
2. 핵심 특징 & 기능 분석
Spring Boot 3.x가 가져온 주요 변화를 5가지로 정리해보겠습니다.
2-1. Jakarta EE 10 기반 전환
가장 파급력이 큰 변화입니다. javax.servlet, javax.persistence, javax.validation 등 모든 Java EE 관련 패키지가 jakarta.*로 변경되었습니다.
단순 텍스트 치환처럼 보이지만, 서드파티 라이브러리 호환성까지 연쇄적으로 영향을 줍니다.
// Spring Boot 2.x
import javax.servlet.http.HttpServletRequest;
import javax.persistence.Entity;
import javax.validation.constraints.NotNull;
// Spring Boot 3.x
import jakarta.servlet.http.HttpServletRequest;
import jakarta.persistence.Entity;
import jakarta.validation.constraints.NotNull;
2-2. Java 17 최소 요구사항
Spring Boot 3.x는 Java 17을 최소 버전으로 요구합니다.
이를 통해 Sealed Class, Pattern Matching for instanceof, Text Block, Record 등 모던 자바 기능을 프레임워크 내부에서 적극 활용합니다.
실무적으로는 Java 21 LTS 사용을 권장합니다.
2-3. GraalVM 네이티브 이미지 공식 지원
Spring Boot 3.x는 AOT(Ahead-of-Time) 컴파일과 GraalVM 네이티브 이미지를 1급 시민으로 지원합니다.
기존 JVM 기반 애플리케이션의 시작 시간이 수 초에서 수십 밀리초로 단축되며, 메모리 사용량도 대폭 감소합니다.
서버리스 환경이나 Kubernetes 기반 마이크로서비스에서 큰 이점을 제공합니다.
2-4. Observability 통합 (Micrometer Observation API)
Spring Boot 3.x는 Micrometer의 Observation API를 통해 메트릭, 로깅, 트레이싱을 하나의 API로 통합 관리합니다.
기존에 각각 별도로 설정해야 했던 분산 트레이싱(Zipkin, Jaeger)과 메트릭(Prometheus) 수집을 일관된 방식으로 처리할 수 있습니다.
2-5. 문제 세부사항 표준 (RFC 7807)
Spring Boot 3.x는 HTTP API 에러 응답에 RFC 7807(Problem Details for HTTP APIs) 표준을 기본 적용합니다. ProblemDetail 클래스를 통해 구조화된 에러 응답을 제공하며, 클라이언트가 에러를 일관되게 처리할 수 있도록 합니다.
![[Spring Boot] 3.x 마이그레이션 설치방법 - 실무에서 겪는 문제와 해결법 실전 체크리스트](https://blog.kakaocdn.net/dna/kOHAH/dJMcajuQEIq/AAAAAAAAAAAAAAAAAAAAAAbblREtCXtfyoXPShCsW5VS9AY8SzMOyInIgi5VfpIQ/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&expires=1774969199&allow_ip=&allow_referer=&signature=Ia5R9i59ir%2BTKcOLWqeadyfcph4%3D)
3. 기술 아키텍처 & 동작 원리
마이그레이션 구성 요소
| 구성 요소 | Spring Boot 2.x | Spring Boot 3.x | 비고 |
|---|---|---|---|
| Java 버전 | Java 8+ | Java 17+ | 필수 업그레이드 |
| Spring Framework | 5.x | 6.x | 자동 전환 |
| Hibernate | 5.x | 6.x | HQL 문법 변경 있음 |
| Tomcat | 9.x | 10.x | Jakarta Servlet 6.0 |
| Jakarta EE | javax. | jakarta. | 전 패키지 변경 |
| Security | 5.x | 6.x | 설정 방식 대폭 변경 |
| Actuator | /actuator/ | /actuator/ | 엔드포인트 일부 변경 |
Spring Boot 3.x 마이그레이션 프로세스 구조
마이그레이션은 크게 빌드 설정 → 소스 코드 변환 → 의존성 정합성 확인 → 테스트 검증의 흐름으로 진행됩니다.
아래는 Gradle 기준 빌드 설정 변경의 핵심입니다.
// build.gradle - Spring Boot 3.x 마이그레이션 설정
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.5'
id 'io.spring.dependency-management' version '1.1.4'
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
// Micrometer Tracing (3.x 신규)
implementation 'io.micrometer:micrometer-tracing-bridge-brave'
implementation 'io.zipkin.reporter2:zipkin-reporter-brave'
// Hibernate 6.x는 spring-boot-starter-data-jpa에 자동 포함
runtimeOnly 'com.mysql:mysql-connector-j' // groupId 변경: mysql → com.mysql
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
}
tasks.named('test') {
useJUnitPlatform()
}
설계 원칙 4가지
- 점진적 마이그레이션: 한 번에 모든 것을 바꾸지 않고, 모듈 단위로 순차 전환합니다. 멀티 모듈 프로젝트라면 공통 모듈부터 시작합니다.
- 자동화 도구 활용: OpenRewrite 같은 자동 리팩토링 도구를 사용해
javax→jakarta변환을 자동화합니다. 수작업보다 정확하고 빠릅니다. - 테스트 우선 검증: 마이그레이션 전 테스트 커버리지를 확보하고, 변환 후 전체 테스트 스위트를 실행하여 리그레션을 조기에 발견합니다.
- 호환성 레이어 유지: 즉시 전환이 어려운 서드파티 라이브러리가 있다면, 어댑터 패턴을 통해 단계적으로 전환합니다.
4. 실무 활용 가이드
OpenRewrite를 활용한 자동 마이그레이션
실무에서 가장 효과적인 마이그레이션 방법은 OpenRewrite를 활용하는 것입니다.
수백 개의 파일에서 javax를 jakarta로 수동 변경하는 것은 비효율적이며 실수가 발생하기 쉽습니다.
// build.gradle에 OpenRewrite 플러그인 추가
plugins {
id 'org.openrewrite.rewrite' version '6.11.2'
}
dependencies {
rewrite 'org.openrewrite.recipe:rewrite-spring:5.8.0'
}
rewrite {
activeRecipe(
'org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_2'
)
}
// 실행: ./gradlew rewriteRun
// Dry-run: ./gradlew rewriteDryRun (변경사항 미리보기)
OpenRewrite의 UpgradeSpringBoot_3_2 레시피는 다음을 자동으로 처리합니다:
javax.→jakarta.패키지 변환- Spring Security 설정 방식 변경 (deprecated API 대체)
spring.factories→META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports전환- Property명 변경 (예:
spring.redis.→spring.data.redis.)
기존 환경 도입 4단계
| 단계 | 작업 내용 | 소요 기간 (중규모 기준) | 핵심 체크포인트 |
|---|---|---|---|
| 1단계 | Java 17+ 업그레이드 및 빌드 확인 | 1~2일 | 모든 모듈 Java 17 컴파일 성공 여부 |
| 2단계 | OpenRewrite로 자동 변환 실행 | 0.5일 | DryRun 결과 리뷰, 변환 파일 수 확인 |
| 3단계 | 수동 수정 (Security, 커스텀 코드) | 2~5일 | Security Config, 커스텀 필터, Hibernate 쿼리 |
| 4단계 | 통합 테스트 및 스테이징 검증 | 2~3일 | 전체 API 테스트, 성능 벤치마크 |
팀 활용 팁
- 브랜치 전략: 마이그레이션 전용 장기 브랜치를 생성하고, main 브랜치의 변경사항을 주기적으로 머지합니다. Feature Flag를 활용해 점진적으로 트래픽을 전환하는 것도 좋은 방법입니다.
- 코드 리뷰 분할: OpenRewrite 자동 변환 결과는 별도 PR로 분리하고, 수동 변경 부분만 상세 리뷰합니다.
- 롤백 계획 수립: 마이그레이션 후 치명적 이슈 발생 시 즉시 롤백할 수 있도록 Blue-Green 배포 또는 Canary 배포를 준비합니다.
5. 경쟁 기술 비교 분석
Spring Boot 3.x vs 대안 프레임워크
| 비교 항목 | Spring Boot 3.x | Quarkus 3.x | Micronaut 4.x | Vert.x 4.x |
|---|---|---|---|---|
| Java 최소 버전 | Java 17 | Java 17 | Java 17 | Java 11 |
| 네이티브 이미지 | GraalVM 공식 지원 | 1급 지원 (빌드 내장) | 1급 지원 (빌드 내장) | 부분 지원 |
| 시작 시간 (JVM) | ~1.5초 | ~0.8초 | ~0.9초 | ~0.5초 |
| 시작 시간 (Native) | ~0.1초 | ~0.03초 | ~0.05초 | N/A |
| 메모리 사용 (JVM) | ~150MB | ~80MB | ~90MB | ~60MB |
| 생태계 성숙도 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
| 기업 채택률 | 매우 높음 | 높음 (Red Hat) | 중간 | 중간 |
| 리액티브 지원 | WebFlux | Mutiny | Reactor/RxJava | 네이티브 비동기 |
| 학습 곡선 | 낮음 (풍부한 자료) | 중간 | 중간 | 높음 |
| DI 방식 | 런타임 리플렉션 | 빌드 타임 CDI | 빌드 타임 DI | 없음 (수동) |
선택 가이드
- Spring Boot 3.x를 선택해야 할 때: 기존 Spring 생태계 투자가 크고, 팀의 Spring 경험이 풍부하며, 엔터프라이즈 수준의 안정성과 서드파티 통합이 필요한 경우입니다. 대부분의 기업용 백엔드 서비스에 적합합니다.
- Quarkus를 고려할 때: Red Hat/OpenShift 환경에서 운영하거나, 서버리스 함수 개발이 주 목적이고, 네이티브 이미지 빌드 시간과 크기 최적화가 중요한 경우입니다.
- Micronaut을 고려할 때: 마이크로서비스 아키텍처에서 초경량 서비스가 필요하고, IoT 엣지 컴퓨팅 등 리소스가 제한된 환경에서 동작해야 하는 경우입니다.
6. 도입 시 베스트 프랙티스
5가지 원칙
원칙 1: Spring Boot 2.7.x를 경유하라
Spring Boot 2.5나 2.6에서 바로 3.x로 점프하지 마십시오. 2.7.x는 3.x 마이그레이션을 위한 "디딤돌" 버전입니다. deprecated 경고가 3.x에서 제거될 API를 미리 알려주므로, 먼저 2.7.x로 올린 후 deprecated 경고를 모두 해소하고 3.x로 전환하는 것이 안전합니다.
원칙 2: Spring Security 설정을 먼저 리팩토링하라
Spring Security 6.x에서 WebSecurityConfigurerAdapter가 완전히 제거되었습니다.
컴포넌트 기반 Security 설정으로 전환해야 합니다.
// ❌ Spring Boot 2.x (deprecated, 3.x에서 제거됨)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/public/**").permitAll()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
}
// ✅ Spring Boot 3.x (컴포넌트 기반 Security 설정)
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults())
.httpBasic(Customizer.withDefaults());
return http.build();
}
@Bean
public AuthenticationManager authenticationManager(
AuthenticationConfiguration authConfig) throws Exception {
return authConfig.getAuthenticationManager();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
원칙 3: Property 변경사항을 꼼꼼히 확인하라
Spring Boot 3.x에서 다수의 프로퍼티명이 변경되었습니다. spring-boot-properties-migrator를 활용하면 런타임에 호환성 매핑과 경고를 받을 수 있습니다.
원칙 4: Hibernate 6.x의 묵시적 변경 사항을 파악하라
Hibernate 6.x로 전환되면서 ID 생성 전략이 변경되었습니다.
기존 GenerationType.AUTO가 MySQL에서 TABLE 전략 대신 SEQUENCE를 선호하도록 바뀌어, 기존 테이블과의 ID 충돌이 발생할 수 있습니다.
원칙 5: 단계별 테스트 검증을 반드시 수행하라
자동 변환 후 반드시 단위 테스트 → 통합 테스트 → E2E 테스트 순서로 검증합니다.
특히 JPA 관련 테스트에서 Hibernate 6.x의 쿼리 생성 변경으로 인한 실패가 빈번합니다.
흔한 실수와 해결 방법
| 실수 | 증상 | 해결 방법 |
|---|---|---|
| javax 임포트 잔존 | ClassNotFoundException: javax.servlet.Filter |
OpenRewrite 재실행 후 수동 검색으로 잔존 javax 확인 |
| Hibernate ID 전략 미수정 | 신규 레코드 INSERT 시 ID 충돌 또는 시퀀스 미존재 에러 | @GenericGenerator 또는 spring.jpa.hibernate.use-new-id-generator-mappings=false 설정 |
| Spring Security 설정 미전환 | 컴파일 에러 WebSecurityConfigurerAdapter not found |
SecurityFilterChain 빈 방식으로 전환 |
| spring.factories 미전환 | Auto-configuration 클래스가 로드되지 않음 | META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 파일 생성 |
| MySQL 드라이버 좌표 미변경 | ClassNotFoundException: com.mysql.jdbc.Driver |
mysql:mysql-connector-java → com.mysql:mysql-connector-j로 변경 |
7. 향후 전망 & 발전 방향
발전 방향 4가지
1. Virtual Thread 완전 통합 (Java 21+)
Spring Boot 3.2부터 Virtual Thread를 공식 지원하며, spring.threads.virtual.enabled=true 한 줄로 활성화할 수 있습니다.
기존 리액티브 프로그래밍(WebFlux)의 성능 이점을 동기 코드 스타일로 얻을 수 있어, 많은 팀이 WebFlux에서 MVC + Virtual Thread로 회귀하고 있습니다.
Spring Boot 3.3~3.4에서는 Virtual Thread 기반의 HTTP 클라이언트 통합이 더욱 강화될 전망입니다.
2. CRaC(Coordinated Restore at Checkpoint) 지원
GraalVM 네이티브 이미지의 대안으로, JVM 위에서 체크포인트/복원 메커니즘을 활용하는 CRaC 프로젝트와의 통합이 진행 중입니다.
기존 JVM의 풍부한 모니터링 도구를 유지하면서도 밀리초 단위 시작 시간을 달성할 수 있는 기술입니다.
3. Declarative HTTP Client 확대
Spring Boot 3.x에서 도입된 @HttpExchange 기반의 선언적 HTTP 클라이언트가 점차 확대되고 있습니다.
Feign Client를 대체할 수 있는 Spring 네이티브 솔루션으로, 향후 리트라이, 서킷 브레이커 등의 레질리언스 패턴과 더 깊이 통합될 것입니다.
4. AI/ML 통합 (Spring AI)
Spring AI 프로젝트가 빠르게 발전하며 Spring Boot 생태계에 편입되고 있습니다.
OpenAI, Anthropic Claude, Ollama 등 다양한 LLM과의 통합을 Spring 방식의 추상화로 제공하며, RAG(Retrieval-Augmented Generation), 벡터 데이터베이스 연동 등을 손쉽게 구현할 수 있습니다.
개발자에게 주는 시사점
Spring Boot 3.x 마이그레이션은 선택이 아닌 필수입니다.
보안 패치 중단이라는 현실적인 이유 외에도, Virtual Thread, GraalVM 네이티브 이미지, Observability 통합 등 생산성과 성능을 크게 향상시킬 수 있는 기능들이 3.x에만 제공됩니다.
마이그레이션을 미루면 미룰수록 기술 부채가 누적되고, 한 번에 전환해야 할 변경사항이 더 많아집니다.
지금이 가장 적절한 전환 시점입니다.
마무리
Spring Boot 3.x 마이그레이션의 핵심을 정리하면 다음과 같습니다:
- Spring Boot 3.x는 Java 17 필수, Jakarta EE 네임스페이스 전환이 가장 큰 변화점입니다
- OpenRewrite 자동 마이그레이션 도구를 활용하면 수작업 실수를 크게 줄일 수 있습니다
- Spring Security 설정 방식 변경과 Hibernate 6.x ID 전략 변경이 실무에서 가장 많은 이슈를 발생시킵니다
- Spring Boot 2.x 지원 종료로 인해 마이그레이션은 선택이 아닌 보안과 생산성을 위한 필수 과정입니다
혹시 Spring Boot 3.x 마이그레이션을 진행하시면서 겪은 문제나 궁금한 점이 있으시다면, 댓글로 남겨주세요!
경험을 함께 나누면 더 좋은 해결책을 찾을 수 있습니다.
이 글이 도움이 되셨다면 공유도 부탁드립니다.
감사합니다!
'개발&프로그래밍' 카테고리의 다른 글
| [Obsidian] 심층 분석 — 아키텍처와 실전 활용 (0) | 2026.03.31 |
|---|---|
| [Obsidian 입문 가이드 초보자를 위한 시작하기] vs 대안 기술 비교 — 어떤 상황에서 선택할까 (1) | 2026.03.31 |
| [Claude] bkit Vibecoding Kit 완벽 가이드: Claude Code PDCA 플러그인으로 AI 바이브코딩 품질 관리하기 (0) | 2026.03.31 |
| [Cloudflare] Pages + D1 사용방법 - 풀스택 웹앱 배포하기 [2편] (0) | 2026.03.27 |
| [Cloudflare] Workers 설치방법 - 서버리스 엣지 컴퓨팅 시작하기 [1편] (0) | 2026.03.27 |
댓글