Spring Boot 2 → 3 마이그레이션 실전 가이드

Spring Boot 2에서 3으로 업그레이드할 때 반드시 처리해야 하는 Jakarta EE 전환, Security 설정 변경, Properties 키 수정을 단계별 코드와 함께 완전히 안내합니다.

· 5 min read · PALDYN Team

지난 글에서 Spring 4부터 6까지 버전별 핵심 변경사항을 살펴봤다. 이번 글에서는 실제 프로젝트에서 Spring Boot 2를 Spring Boot 3으로 업그레이드하는 전 과정을 실전 코드와 함께 단계별로 안내한다.

마이그레이션 전 필수 확인사항

Spring Boot 3 마이그레이션은 단순한 버전 숫자 변경이 아니다. Java 17 이상, Jakarta EE 9+, Spring Framework 6이 동시에 요구된다. 시작 전에 다음을 확인한다.

  • 현재 JDK 버전: Java 17 미만이면 JDK 업그레이드를 먼저 진행
  • 현재 Spring Boot 버전: 2.5 이하라면 2.7로 먼저 올린 뒤 3.0으로 이동
  • 3rd-party 라이브러리: Jakarta EE 9 호환 버전 제공 여부 확인
  • 테스트 커버리지: 마이그레이션 후 회귀 검증을 위해 70% 이상 권장

Spring Boot 버전 범프

pom.xml의 부모 버전을 변경한다.

<!-- 변경 전 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.18</version>
</parent>

<!-- 변경 후 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.3.0</version>
</parent>

Gradle을 사용한다면:

// build.gradle.kts
plugins {
    id("org.springframework.boot") version "3.3.0"
    id("io.spring.dependency-management") version "1.1.5"
}

Breaking Change 1: Jakarta EE 패키지 전환

가장 광범위한 변경이다. javax.*로 시작하는 모든 import가 jakarta.*로 바뀐다.

// 변경 전 (javax.*)
import javax.servlet.http.HttpServletRequest;
import javax.servlet.Filter;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.transaction.Transactional;

// 변경 후 (jakarta.*)
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.Filter;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.transaction.Transactional;

파일 수가 많다면 OpenRewrite로 자동화한다.

<!-- pom.xml에 추가 -->
<plugin>
    <groupId>org.openrewrite.maven</groupId>
    <artifactId>rewrite-maven-plugin</artifactId>
    <version>5.40.0</version>
    <configuration>
        <activeRecipes>
            <recipe>org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_3</recipe>
        </activeRecipes>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>org.openrewrite.recipe</groupId>
            <artifactId>rewrite-spring</artifactId>
            <version>5.20.0</version>
        </dependency>
    </dependencies>
</plugin>
# 자동 변환 실행
./mvnw rewrite:run

Breaking Change 2: Spring Security 6 설정 변경

Security 설정 마이그레이션 Before / After

WebSecurityConfigurerAdapter가 Spring Security 6에서 완전히 제거됐다. SecurityFilterChain Bean 방식으로 변경해야 한다.

// 변경 전 (Boot 2 / Security 5)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll()
                .antMatchers("/api/**").authenticated()
                .anyRequest().denyAll()
            .and()
            .formLogin()
                .loginPage("/login")
                .defaultSuccessUrl("/dashboard")
            .and()
            .logout()
                .logoutSuccessUrl("/login");
    }
}

// 변경 후 (Boot 3 / Security 6)
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/public/**").permitAll()
                .requestMatchers("/api/**").authenticated()
                .anyRequest().denyAll()
            )
            .formLogin(form -> form
                .loginPage("/login")
                .defaultSuccessUrl("/dashboard")
            )
            .logout(logout -> logout
                .logoutSuccessUrl("/login")
            );
        return http.build();
    }
}

핵심 변경 API:

  • authorizeRequests()authorizeHttpRequests()
  • antMatchers()requestMatchers()
  • .and() 체이닝 → 람다 설정 블록
  • 메서드 재정의 → SecurityFilterChain Bean 반환

Breaking Change 3: application.properties 키 변경

많은 설정 키가 리네임됐다.

# 변경 전 (Boot 2)
spring:
  redis:
    host: localhost
    port: 6379
  mvc:
    pathmatch:
      use-suffix-pattern: false
  datasource:
    initialization-mode: always

# 변경 후 (Boot 3)
spring:
  data:
    redis:
      host: localhost
      port: 6379
  mvc:
    pathmatch:
      use-suffix-pattern: false  # 제거됨, 설정 불필요
  sql:
    init:
      mode: always

주요 변경된 키 목록:

  • spring.redis.*spring.data.redis.*
  • spring.mongodb.*spring.data.mongodb.*
  • spring.elasticsearch.*spring.elasticsearch.uris
  • spring.datasource.initialization-modespring.sql.init.mode

Breaking Change 4: Actuator 기본 노출 변경

Boot 3에서 Actuator 엔드포인트의 기본 노출 범위가 강화됐다.

# 필요한 엔드포인트를 명시적으로 노출
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
  endpoint:
    health:
      show-details: when-authorized

신기능 활성화

마이그레이션 완료 후 Boot 3의 새 기능을 설정으로 활성화한다.

# application.yml
spring:
  threads:
    virtual:
      enabled: true  # Virtual Threads (JDK 21 필요)
  mvc:
    problemdetails:
      enabled: true  # RFC 7807 Problem Details
  docker:
    compose:
      enabled: true  # Docker Compose 자동 연동

마이그레이션 체크리스트

Spring Boot 2 → 3 마이그레이션 체크리스트

마이그레이션 완료 후 검증 절차:

# 1. 전체 빌드 확인
./mvnw clean package

# 2. 테스트 실행
./mvnw test

# 3. 애플리케이션 기동 확인
./mvnw spring-boot:run

# 4. Actuator health 확인
curl http://localhost:8080/actuator/health

# 5. 주요 API 엔드포인트 스모크 테스트
curl http://localhost:8080/api/users

서드파티 라이브러리가 Jakarta EE 9을 지원하는 버전으로 업그레이드됐는지 확인한다. 특히 Hibernate 6+, Flyway 9+, MyBatis 3.5.11+ 등은 Jakarta EE 호환 버전이 별도로 제공된다.

Spring Boot 2 → 3 마이그레이션은 한 번의 작업으로 Java 17, Jakarta EE, Spring 6의 모든 현대화 혜택을 동시에 얻을 수 있는 의미 있는 투자다.


지난 글: Spring 4 · 5 · 6 핵심 변경사항 총정리

다음 글: Spring 점진적 현대화: 레거시에서 최신 Spring까지


읽어주셔서 감사합니다. 😊