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

레거시 Spring 프로젝트를 최신 Spring Boot 3와 클라우드 네이티브 아키텍처로 단계적으로 전환하는 전체 전략과 실무 경험을 정리합니다.

· 8 min read · PALDYN Team

지난 글에서 Spring Boot 2에서 3으로 업그레이드하는 구체적인 절차를 살펴봤다. 이번 글에서는 더 넓은 시각에서 레거시 Spring 프로젝트를 현대화하는 전략, 실무 경험, 그리고 우리가 Spring을 배워온 여정을 돌아본다.

현대화가 필요한 순간

레거시 Spring 프로젝트를 현대화해야 하는 시점을 어떻게 판단할 수 있을까. 아래 신호 중 두 가지 이상이 해당된다면 현대화를 진지하게 고려할 때다.

  • Java 8 이하 또는 Spring 4 이하를 사용 중
  • 배포에 WAR 파일과 외부 WAS(Tomcat, JBoss)가 필요
  • 신규 개발자의 온보딩 시간이 2주 이상
  • 단위 테스트보다 통합 테스트 비율이 높고, 테스트 실행이 느림
  • applicationContext.xml이 500줄을 넘음
  • Spring Boot EOL 경고를 무시한 지 6개월 이상

현대화는 리스크가 따르지만, 현대화를 하지 않는 것도 리스크다. 보안 패치 지연, 인재 채용 어려움, 개발 생산성 저하가 시간이 지날수록 커진다.

전체 현대화 로드맵

Spring 점진적 현대화 로드맵

현대화를 한 번에 시도하면 실패한다. 가장 성공 확률이 높은 방식은 4단계 점진적 접근이다.

Phase 1: 현황 분석과 기준선 수립

코드를 단 한 줄도 바꾸지 말고 먼저 측정한다.

# 프로젝트 구조 파악
find . -name "*.java" | wc -l
find . -name "*.xml" | grep -v target | wc -l

# 의존성 취약점 스캔 (OWASP)
./mvnw org.owasp:dependency-check-maven:check

# 테스트 커버리지 측정
./mvnw verify jacoco:report
open target/site/jacoco/index.html

기준선이 없으면 개선을 증명할 수 없다. 현재 빌드 시간, 시작 시간, 주요 API 응답 시간을 기록해 두자.

Phase 2: Java 버전 업그레이드

Java 버전은 독립적으로 올릴 수 있다. Spring 버전을 건드리지 않고 Java 8 → 11 → 17 → 21 순서로 올린다.

<!-- Maven: Java 버전 설정 -->
<properties>
    <java.version>17</java.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
</properties>

Java 11에서 주의할 점: javax.xml.bind (JAXB), javax.activation (JAF)이 JDK에서 제거됐다. 별도 의존성을 추가해야 한다.

<!-- Java 11 이상에서 JAXB 필요 시 -->
<dependency>
    <groupId>jakarta.xml.bind</groupId>
    <artifactId>jakarta.xml.bind-api</artifactId>
    <version>4.0.2</version>
</dependency>

Java 17의 새 기능(Records, Sealed Classes, Text Blocks)을 활용하면 코드 품질이 눈에 띄게 향상된다.

// Java 16+ Record 활용 (DTO 간결화)
public record UserDto(Long id, String name, String email) {}

// Java 15+ Text Block 활용 (SQL, JSON 가독성 향상)
String sql = """
    SELECT u.id, u.name, u.email
    FROM users u
    WHERE u.active = true
    ORDER BY u.created_at DESC
    """;

Phase 3: Spring Boot 현대화

Java 버전이 안정화됐으면 Spring Boot를 올린다. 지난 글에서 다룬 Boot 2→3 마이그레이션 절차를 모듈별로 적용한다.

// Spring Boot 3의 @SpringBootApplication — 변경 없음
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

이 단계에서 OpenRewrite를 최대한 활용한다.

# Boot 3.3으로 일괄 업그레이드 (javax→jakarta, 설정 키, Security API)
./mvnw rewrite:run -Drewrite.activeRecipes=\
org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_3

# 변경 사항 확인
git diff --stat

Phase 4: 클라우드 네이티브 완성

이 단계는 필수가 아니라 선택이다. 팀의 역량과 비즈니스 요구에 맞게 적용한다.

# Virtual Threads 활성화 (JDK 21, Boot 3.2+)
spring:
  threads:
    virtual:
      enabled: true

# Micrometer Observability 설정
management:
  tracing:
    sampling:
      probability: 1.0
  zipkin:
    tracing:
      endpoint: http://zipkin:9411/api/v2/spans

자동화 도구 활용

OpenRewrite 자동 마이그레이션 전략

현대화 작업의 반복적이고 기계적인 부분은 도구에 맡긴다.

OpenRewrite: Java 코드 변환 자동화

# 사용 가능한 Spring Boot 관련 레시피 목록 확인
./mvnw rewrite:discover -Drecipe=org.openrewrite.java.spring

Dependabot: 의존성 최신화 자동화

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "maven"
    directory: "/"
    schedule:
      interval: "weekly"
    groups:
      spring:
        patterns:
          - "org.springframework*"

Spring Boot Migration Guide: 공식 마이그레이션 가이드를 버전별로 제공한다. spring.io/guides에서 항상 최신 정보를 확인한다.

현대화 성공을 위한 조직적 접근

기술 현대화는 기술 문제만이 아니다. 다음 사항이 갖춰지지 않으면 기술이 아무리 좋아도 실패한다.

비즈니스 케이스 수립: 현대화의 ROI를 수치로 제시하라. “Java 17로 올리면 Virtual Threads로 서버 비용 30% 절감 가능” 같은 구체적 수치가 경영진 설득에 효과적이다.

점진적 적용, 빠른 피드백: 전체 마이그레이션을 한 번에 하지 말고, 마이크로서비스라면 트래픽이 적은 서비스부터, 모놀리스라면 도메인 모듈 단위로 나눠 적용하라.

Feature Flag: 현대화된 새 코드와 레거시 코드를 동시에 운영하면서 점진적으로 트래픽을 이동시키는 방식이 안전하다.

@Service
public class UserService {

    private final LegacyUserRepository legacyRepo;
    private final ModernUserRepository modernRepo;
    private final FeatureFlags flags;

    public User findById(Long id) {
        if (flags.isEnabled("use-modern-repo")) {
            return modernRepo.findById(id).orElseThrow();
        }
        return legacyRepo.findById(id);
    }
}

Spring 학습을 정리하며

그동안 Spring의 철학과 기본 원리(IoC/DI, AOP)에서 시작해 Spring MVC, Spring Data JPA, Spring Boot, Spring Security, 캐시·비동기·이벤트, 테스트 전략, 운영 관측, Cloud Native, Spring WebFlux, 그리고 현대화 전략까지 152개의 글로 Spring 생태계 전체를 다뤘다.

# Spring 완전 정복 시리즈 통계
# - 총 포스트: 152편
# - 다룬 주제: IoC/DI, AOP, MVC, Security, JPA, Boot, Cloud, Reactive, AI...
# - 목표: 현업에서 Spring을 자신 있게 사용할 수 있는 실력

Spring은 계속 진화한다. Spring 6.x 업데이트, Spring Boot 4.x 예고, Spring AI의 급격한 발전 등 변화의 속도가 빠르다. 하지만 첫 글에서 다룬 IoC/DI의 철학, 테스트 가능한 코드, 횡단 관심사의 분리라는 원칙은 버전이 바뀌어도 흔들리지 않는다.

공식 문서(docs.spring.io), Spring 공식 블로그, 그리고 실제 프로젝트에서의 실습이 학습의 완성이다. 이 글들이 Spring 마스터로 가는 여정에 탄탄한 디딤돌이 되기를 바란다.


지난 글: Spring Boot 2 → 3 마이그레이션 실전 가이드


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