- 계좌번호 암복호화 요건 적용을 위한 라이브러리 등록을 진행하면서, Endecrypt 모듈을 새로 생성하고, 생성한 모듈을 insuAPI 에서 외부 라이브러리로 클래스 로드해서 읽을 수 있도록 했습니다. 그런데 insuAPI 에서 클래스 로드를 하지 못하고 ClassNotFoundException이 발생했습니다. 해당 문제를 해결하면서 살펴본 원인, 해결 방법, 설정한 내용을 공유 드립니다.
1. 스프링 부트 런처
Java는 “JAR 파일 안에 여러 JAR 파일이 묶여 있는 파일”을 불러오는 표준 방법이 없습니다. 그래서 스프링 부트가 지원하는 “런처”를 통해서 JAR 속 JAR 를 읽어올 수 있습니다.
스프링 부트에서는 3가지 유형의 런처(JarLauncher, WarLauncher, PropertiesLauncher)를 제공합니다. 이 런처는 실행가능한 JAR 파일에 포함되어 의존 라이브러리로부터 있는 자원(.class 및 기타 파일)을 찾아서 가져옵니다.
JarLauncher는 BOOT-INF/lib를 찾아보고 WarLauncher는 WEB-INF/lib를 탐색합니다.
PropertiesLauncher의 경우 BOOT-INF/lib를 탐색하고, 추가적으로 환경변수 LOADER_PATH 혹은 자바 변수 -Dloader.path 속성을 통해 정의할 수 있습니다.
스프링 부트 런처 3가지
JarLauncher , WarLauncher , PropertiesLauncher
런처가 탐색하는 구간
JarLauncher > BOOT-INF/lib
WarLauncher > WEB-INF/lib
PropertiesLauncher > BOOT-INF/lib + loader.path
실행 가능한 JAR 구조
example.jar
|
+-META-INF
| +-MANIFEST.MF
+-org
| +-springframework
| +-boot
| +-loader
| +-<spring boot loader classes>
+-BOOT-INF
+-classes
| +-mycompany
| +-project
| +-YourClasses.class
+-lib
+-dependency1.jar
+-dependency2.jar
*class 파일은 BOOT-INF/classes에, dependencies 는 BOOT-INF/lib 디렉토리에 적재
2. Maven 빌드의 layout 설정
Maven 빌드에서 layout 설정은 아카이브 유형을 지정하는 설정입니다.
layout 지정 가능한 종류
JAR, WAR, ZIP, DIR, MODULE, NONE
- ZIP(alias to DIR): 를 JAR사용하는 레이아웃 과 유사하지만 PropertiesLauncher 를 사용합니다.
- JAR: 일반 실행 가능한 JAR 레이아웃.
- WAR: 실행 가능한 WAR 레이아웃. 서블릿 컨테이너에 배포될 때 충돌을 피하기 위해 provided종속성이 배치됩니다 .WEB-INF/lib-providedwar
- MODULE 스코프 지정으로 지정한 dependency 및 프로젝트 리소스를 빌드합니다.
- NONE: 모든 dependency 및 프로젝트 리소스를 빌드합니다.
<project>
<!-- ... -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layout>ZIP</layout><!-- to support PropertiesLaunchar -->
</configuration>
</plugin>
</plugins>
</build>
</project>
3. <layout>ZIP 으로 설정 시 PropertiesLauncher
JAR로 배포하는 경우에는 JarLauncher가 기본구성,
WAR로 배포하는 경우에는 WarLauncher가 기본구성입니다.
Maven 빌드 시 <layout>ZIP 설정을 하면
MANIFEST.MF 문서 내 Main-Class 가 PropertiesLauncher 로 지정됩니다.
<layout>ZIP</layout> 설정없이 기본값으로 빌드 한 경우:
Main-Class: org.springframework.boot.loader.JarLauncher
<layout>ZIP</layout> 설정하고 빌드 한 경우 :
Main-Class: org.springframework.boot.loader.**PropertiesLauncher**
4. loader.path 설정
loader.path 는 JVM 옵션 대신 application.properties을 통해서 클래스 경로를 설정합니다.
loader.path 디렉토리를 지정하면 해당 디렉토리에 있는 jar 및 zip 파일에 대해 재귀적으로 스캔합니다. 중복 경로 입력 시, 콤마(,) 로 구분할 수 있습니다. 아카이브 경로 또는 와일드카드 패턴을 포함할 수도 있습니다.
loader.path 에 설정을 하지 않으면, BOOT-INF/lib 를 탐색하는 JarLauncher 와 동일하게 동작합니다.
insuService.sh 에 입력한 loader.path 지정 예시
#######################
#0. constants Set
#######################
CRYPTDIR=${BASE}/endecrypt
########################
# linux sh #
########################
# -Dloader.path 추가 , 위치는 exec $JDK_PATH/bin/java 뒤
-Dloader.path=${CRYPTDIR}
# 또는 -Dloader.path=/home/test/base/endecrypt/
loader.path 중복 사용 예시 (, 로 구분)
java -Dloader.path=WEB-INF/lib-provided,WEB-INF/lib,WEB-INF/classes,file:lib/
insu.yml에 입력한 loader.path 지정 > 지원하지 않음**
insu.yml에 아래와 같이 입력했을 시에는 동작하지 않습니다.
loader:
path: /home/test/base/endecrypt/
loader.path는 애플리케이션 실행 시점에 클래스 로더에 추가로 로드할 JAR 파일 또는 디렉토리 경로를 지정합니다. 만약 properties 파일에서 loader.path를 지정하고자 한다면, 해당 설정을 자바 애플리케이션의 초기화 단계에 읽어올 수 있도록 직접 처리해야 합니다.
loader.path 와 그 외 몇 가지 설정값에 대한 추가 내용
- loader.path는 loader.properties위치를 찾는 데에 사용할 수는 없습니다. (자동으로 읽어지는properties 의 기본 파일명이 loader.properties)
- PropertiesLauncher 가 실행 될 때, JVM classpath 에서 loader.properties 위치를 찾습니다.
- loader.home은 loader.config.location 이 동착하지 않을때만 추가적인 properties 파일을 찾을 때 사용합니다.
- loader.properties의 속성은 시스템 속성 및 환경 변수로 제공된 속성보다 우선 순위가 낮습니다. 환경 변수가 설정되어 있으면 loader.properties의 속성이 사용되지 않습니다.
- 검색 순서 : environment variables, system properties, loader.properties, the exploded archive manifest, and the archive manifest.
https://github.com/spring-projects/spring-boot/issues/3645
5. 종합
문제 : 외부 라이브러리 추가 시, ClassNotFoundException이 발생합니다.
해결: 1) PropertiesLauncher 를 사용 할 수 있도록,
빌드 단계에서 아카이브 유형 <layout>을 ZIP 으로 설정합니다.
2) 실행 단계에서 `loader.path` 속성으로 외부라이브러리의 path를 지정해줍니다.
*참고 자료
Stackoverflow) Spring Boot Executable JAR - Layout Changes break Classpath
'Spring' 카테고리의 다른 글
circuitBreaker (2) | 2025.02.03 |
---|---|
[Spring Batch] FileNotFoundException, DefaultBatchConfiguration.class (0) | 2023.01.12 |