혹시 jar 파일 실행해 보셨어요??
회사에서 과거 프로젝트와 관련된 업무를 마무리하던 중, 선임분께서 보안상의 이유로 직접 실행이 가능한 jar 파일을 요청하셨다.
나는 그렇게 프로젝트를 빌드하고, jar 파일이 정상적으로 실행되는지 테스트까지 마치고 전달드렸다.
그런데 얼마 지나지 않아 선임분께서 위의 같은 질문과 함께 에러 로그를 보내셨다.
이번 글에서는 에러 로그를 살펴보면서, "jar 파일이 환경에 따라 왜 실행이 안 될 수 있는지" 에 대해 이야기해보려 한다.
1. 에러 로그를 살펴보자
전체 에러 로그를 보면 상당히 기니, 주요 에러 로그만 단계별로 살펴보자.
1) java.lang.IllegalStateException: Cannot load configuration class
- 스프링 애플리케이션이 실행되면서 @SpringBootApplication 클래스 로딩을 시도했지만 실패했다는 에러이다.
- 이 시점에서 스프링은 CGLIB 라이브러리를 사용해 configuration 클래스에 대한 프록시 클래스를 생성하려 하는데, 이 과정에서 문제가 발생한 것이다.
2) Caused by: org.springframework.cglib.core.CodeGenerationException
java.lang.reflect.InaccessibleObjectException
-->Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @7b49cea0
더 구체적으로 보면 위와 같은 로그를 볼 수 있다.
- `java.lang.ClassLoader`에 위치한 `protected final defineClass` 메서드에 접근을 할 수 없다는 에러이다.
- CGLIB가 프록시 클래스 생성하는 과정에서 `defineClass()` 메서드를 리플렉션으로 접근하려 했지만, java 모듈 시스템에 의해 접근하지 못해 에러가 난 것이다.
에러 로그를 살펴보니, 프록시 클래스 생성에 실패하면서, 애플리케이션 실행도 실패했음을 알 수 있었다.
그런데 내가 테스트 할 때는 잘 실행되던 애플리케이션이 선임분께서는 왜 저런 에러를 마주한걸까?
2. java 빌드 환경과 실행 환경
나는 해당 프로젝트의 작업 요청을 받았을 때, java 8 기반인 것을 확인하고, 로컬 환경을 java 8로 맞추어 놓고 빌드와 테스트를 진행했다.
하지만 선임분께서 실행한 환경은 java 8이 아니었다.
즉, 빌드 환경과 실행 환경이 달라 에러가 발생한 것이었다.
Q. 그럼 왜 빌드 환경과 실행 환경에서의 java 버전을 다르게 실행하면 문제가 생기는 걸까?
빌드 환경이 달라지면 생성되는 바이트 코드 또한 달라지고, 이로 인해 여러 호환성 문제가 발생할 수 있다.
하지만 이번에 발생한 문제는 java 9부터 도입된 모듈 시스템 때문이었다.
(물론 실행 환경이 빌드 환경보다 java 버전이 낮을 경우, 최신 버전의 문법이나 기능에 대한 바이트코드를 제대로 해석할 수 없어 실행에 실패할 확률이 매우 높다.)
java 9 이전에는 `java.lang` 가 같은 jdk 내부 패키지에 리플렉션으로 자유롭게 접근할 수 있었지만,
java 9 이후부터는 이러한 패키지들이 모듈로 감싸지게 되면서, 외부에서의 접근이 차단되었다.
결국 스프링의 CGLIB과 같은 외부 라이브러리가 jdk 내부 메서드에 리플렉션으로 접근하려다 실패한 것이다.
반면, java 8에서는 모듈에 대한 개념이 없었기 때문에 CGLIB이 `defineClass()`에 접근해 프록시 클래스를 생성할 수 있었고, 스프링 애플리케이션도 문제 없이 실행이 가능했던 것이다.
💭 마치며
지금까지 크게 고민 없이, 프로젝트에 맞추어 java 버전을 설정하고 작업을 진행했다.
그런데 이번 에러를 살펴보면서, java 버전에 따른 빌드와 실행에 대해 생각해보고, 그리고 새삼 당연하게만 여기던 호환성의 중요성에 대해 느낄 수 있었다. 또 최근에 java 모듈과 gradle 모듈에 대한 글을 썼는데, java 모듈과 관련된 에러가 나와 반갑기도 했다.. ㅎ
'TIL' 카테고리의 다른 글
자바 모듈, Gradle 모듈 무엇이 다를까? (feat. 멀티 모듈) (0) | 2025.05.15 |
---|---|
애플 소셜 로그인 (with. Spring) (1) | 2024.11.05 |
OAuth 2.0 개념, 동작 과정 이해 (1) | 2024.10.31 |
Sysbench 벤치마크 & 테스트 데이터 (for. Mac) (0) | 2024.07.27 |
템플릿 메소드 패턴 vs. 전략 패턴 (0) | 2024.07.14 |