[자바] 24. 선택 : 어떤 자바 버전을 쓸까 (배포판·마이그레이션 정리)

자바 버전 여행 24편 - 어떤 자바 버전을 쓸까

작성자

카테고리:

* 이 게시물은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

(자바 버전 여행 ㉔)

긴 여행의 마지막이다. 8부터 21까지 무엇이 어떻게 바뀌었는지 봤으니, 이제 가장 현실적인 질문에 답할 차례다. 그래서 나는 뭘 깔아야 하나. 정답은 하나가 아니라 상황별로 갈린다.

자바 버전 선택은 결국 몇 버전이냐, 누구의 빌드(배포판)냐 두 갈래다. 자바 8·11·17·21 차이가 가물가물하면 23편의 총정리 표를 옆에 두자.

배포판은 무엇으로

1편에서 봤듯 배포판은 여럿이다. 실무 기준으로 좁히면 이렇다.

배포판라이선스·비용지원이럴 때
Temurin (Adoptium)무료(GPLv2+CE)커뮤니티 주도 LTS 장기 패치일반적인 기본값
Amazon Corretto무료(GPLv2+CE)AWS 자체 로드맵, 특히 8을 길게AWS 환경, 8을 더 끌 때
Azul Zulu무료 빌드+유료 지원 병행유료 계약 시 구버전·비LTS까지상용 지원 계약, 특이 버전
Oracle JDKNFTC(최신 LTS 한시 무료→유료)구독 시 장기Oracle 계약이 있는 조직
BellSoft Liberica무료(GPLv2+CE)LTS 장기 패치경량 컨테이너(Alpine), 스프링 빌드팩 기본

Java LTS 버전의 패치 기한은 벤더마다 다르고 연장도 잦아 일부러 못 박지 않았다 — 2026년 기준, 도입 전 각 벤더 로드맵을 확인하자.

나처럼 서버를 직접 굴린다면 Temurin이나 Corretto가 마음 편하다. 라이선스 걱정 없이 LTS를 길게 받는다. 어느 배포판이든 TCK 인증을 통과한 ‘같은 자바’라는 점도 기억해 두자.

선택을 표로 — 상황별 정리

‘뭘 깔아야 하나’의 답을 한 장으로 압축하면 이렇다.

상황추천
새 프로젝트21(최신 LTS), 보수적이면 17
8·11 레거시17 경유 후 필요 시 21
학습·실험21 — 최신 문법을 다 써볼 수 있음
컨테이너·서버리스21(가상 스레드) + jlink 슬림화
라이브러리 저자타깃은 낮게(8·11), 테스트는 21까지

자바 버전 선택이 실제로 갈리는 다섯 장면을 조금 더 파 보자.

① 신규 프로젝트 → 21

지원 기간이 가장 길게 남았고 가상 스레드·패턴 매칭이 21에서 완성됐다. 2026년 기준 이후 LTS(Java 25)도 나와 있으니 생태계가 따라온 최신 LTS 원칙으로 고르면 된다.

② 8에 묶인 레거시 → 우선 11·17

첫 계단이 가장 험하다 — 11편의 Java EE 모듈 제거가 여기서 터진다. 이 구간만 넘으면 수월해진다. 부트 1.x·2.x가 발목이면 프레임워크 업그레이드가 먼저다.

③ 11에서 갈아탈 타이밍 → 지금

11은 8과 문법 차이가 적어 머물러도 얻는 게 적다. 17이면 record·sealed·텍스트 블록이 열리고, 큰 제거는 11에서 끝나 이행도 순탄하다. 갈 거면 21까지 한 호흡으로.

④ 스프링 부트 3.x → 자동으로 17+

부트 3은 Java 17이 최소선이라 선택의 자유가 없다. javax→jakarta 전환을 동반하는 큰 공사고, 부트 2.x OSS 지원은 끝났다(2023년 말 기준). 이왕이면 21을 목표로 한 번에 끝내자.

⑤ 라이브러리 저자 → 타깃 낮게, 테스트 넓게

애플리케이션과 반대 전략. --release 8로 타깃을 낮게 고정해 저변을 넓히고, CI는 8·11·17·21 매트릭스로 최신 호환을 보증한다. 지원 종료는 다운로드 통계로 정한다.

마이그레이션은 계단으로

8→21을 한 번에 하지 않는다. 8 → 11(빠진 모듈 되살리기) → 17(강한 캡슐화) → 21 순으로 계단을 밟는다. 각 단계마다 테스트를 돌려 무엇이 깨지는지 좁힌다. 라이브러리·빌드 도구부터 최신화하는 게 먼저다.

각 계단에서 실제로 깨지는 지점 셋을 에러 메시지와 함께 보자.

깨짐 ① 8→11 : Java EE 모듈 제거

java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
        at com.example.legacy.XmlConfigLoader.load(XmlConfigLoader.java:23)

JDK에 있던 java.xml.bind 모듈이 11에서 빠진 탓이다. 해결은 같은 API의 외부 의존성 추가.

// build.gradle
implementation 'jakarta.xml.bind:jakarta.xml.bind-api:2.3.3'
runtimeOnly 'org.glassfish.jaxb:jaxb-runtime:2.3.3'

깨짐 ② 11→17 : 강한 캡슐화

java.lang.reflect.InaccessibleObjectException:
  module java.base does not "opens java.lang" to unnamed module @1b6d3586

정공법은 라이브러리 최신화. 급하면 --add-opens java.base/java.lang=ALL-UNNAMED로 임시로 열되, 진통제이니 사유를 적고 백로그에 올린다.

깨짐 ③ 내부 API — sun.misc.Unsafe 경고

WARNING: Illegal reflective access by com.thirdparty.MagicSerializer
WARNING: All illegal access operations will be denied in a future release

11에선 경고지만 17부턴 예고대로 거부되어 위의 ②가 된다. jdeps --jdk-internals app.jar로 내부 API 의존을 전수 조사해 라이브러리를 업데이트하자. 경고 단계인 11에서 잡는 게 요령이다.

직접 해보기 — SDKMAN으로 계단 재현

2편에서 설치한 SDKMAN으로 LTS를 오르내리며 위 깨짐을 직접 밟아 보자.

sdk list java | grep tem     # 식별자는 이 출력 기준(패치 숫자는 바뀜)
sdk install java 11.0.25-tem && sdk install java 17.0.13-tem
sdk use java 11.0.25-tem && ./gradlew test   # 버전 바꿔가며 반복

8 시절 코드는 대개 11 계단에서 깨짐 ①, 17 계단에서 ②가 나오고, 17을 통과하면 21은 조용하다. 한 걸음 더 — 실제 프로젝트 브랜치로 돌리면 초록·빨강 결과가 곧 마이그레이션 견적서다.

✅ 확인 — 깨짐 3종의 에러 메시지를 보고 어느 계단의 문제인지, 첫 대응이 무엇인지 말할 수 있으면 통과다.

자바만 올리지 말고 툴링도 함께

버전 업은 자바 혼자만의 일이 아니다. 빌드 도구(Gradle·Maven), IDE, CI 이미지, 그리고 주요 라이브러리(스프링 등)가 그 버전을 지원하는지 확인해야 한다. 프레임워크가 최소 버전을 요구하기도 한다(스프링 부트 3 = 자바 17+). 생태계를 함께 올리는 게 실전 마이그레이션이다.

단골 사고는 로컬 JDK만 올리고 CI 도커 이미지 태그(eclipse-temurin:8)를 안 올리는 것. Gradle 툴체인으로 요구 버전을 빌드에 못 박아 두자.

여기까지 함께 온 당신은 이제 자바 버전 앞에서 더 이상 헤매지 않을 것이다. 24편, 긴 여행을 끝까지 따라와 줘서 고맙다. — 코즈모

🔧 현장에서 — Java 8·Spring Boot 2 → Java 21·Spring Boot 3 마이그레이션

오래 Java 8 · Spring Boot 2.x · Spring 5 · SpringFox Swagger · 낡은 라이브러리로 운영되던 시스템을 21과 Boot 3으로 한 번에 올린 적이 있다. Java 버전만이 아니라 Spring 생태계 자체가 크게 바뀌어서, 8에선 멀쩡하던 코드가 컴파일·런타임에서 줄줄이 터졌다 — javax.*→jakarta.* 전환, Bean 생성 오류, Reflection 오류, 라이브러리 비호환, SpringFox 문제, 설정 프로퍼티 변경, Deprecated·삭제된 API.

한 개가 아니라 여러 라이브러리의 호환성 문제가 연쇄로 터져서 최초 원인을 찾기가 가장 어려웠다. 그래서 버전만 올리는 방식을 버리고, 전체 Dependency Graph를 점검하는 방식으로 바꿨다. javax를 jakarta로, 라이브러리는 Boot 3 호환 버전으로, 유지 안 되는 건 교체, SpringFox는 제거하고 OpenAPI 계열로, Bean 생성 최초 예외부터 역추적, 그리고 한 번에 다 잡지 않고 계층별로 정상화했다.

교훈 — 대규모 Java/Spring 업그레이드는 JDK를 교체하는 작업이 아니라 사실상 애플리케이션 플랫폼 마이그레이션이다.

여행을 마치며

자바가 버전이 많아 헷갈렸다면, 이제 그 많음이 6개월마다 꾸준히 나아진 흔적이라는 게 보일 것이다. 8이 함수형을 열었고, 11이 정착시켰고, 17이 문법을 현대화했고, 21이 동시성의 판을 바꿨다. 무엇을 고르든, 이 흐름을 알고 고르는 것과 모르고 고르는 것은 다르다.

다음 LTS가 나와도 판단법은 같다 — 생태계를 보고, 계단으로 밟고, 깨지는 지점을 미리 스캔한다. 이 세 문장이 24편의 요약이다.

자주 묻는 질문 (FAQ)

레거시 프로젝트를 어떤 버전으로 올릴까요?

핵심 프레임워크가 지원하는 최소 버전을 확인하고 그 이상의 최신 LTS(17 또는 21)를 고르세요. 테스트를 먼저 돌려 검증합니다.

배포판은 뭘 고르나요?

일반적으로 Temurin, AWS 환경이면 Corretto가 무난합니다. 둘 다 무료이고 LTS를 길게 지원합니다. 지원 연한은 2026년 기준 각 벤더 로드맵에서 확인하세요.

Java 8에서 21로 한 번에 올려도 되나요?

권하지 않습니다. 깨지는 지점이 11(모듈 제거)과 17(강한 캡슐화)에 몰려 있어, 경유하며 계단마다 테스트해야 원인을 분리해 잡을 수 있습니다.

Java LTS 버전은 얼마나 자주 나오나요?

새 버전은 6개월, LTS는 2021년 이후 2년 주기입니다(11→17→21→이후 동일). ‘검증된 최신 LTS’라는 원칙은 다음 LTS에도 그대로 적용됩니다.

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다