Spring/Spring Boot
[Spring Boot] 5. Executable Jars
noahkim_
2023. 10. 13. 19:25
0. spring-boot-loader 모듈
- Spring Boot 애플리케이션을 실행 가능한 JAR 또는 WAR로 만들고 실행할 수 있도록 도와주는 모듈
Gradle Plugin
plugins {
id 'java'
id 'org.springframework.boot' version '3.0.4'
}
- java 플러그인이 적용되어 있을 경우, spring boot 플러그인은 spring-boot-loader 모듈을 자동으로 추가합니다.
1. Nested JARs
- Java는 기본적으로 중첩 jar를 로드하고 압축하는 기능을 제공하지 않습니다.
- 커맨드라인에서 실행할 수 있는 self-contained 애플리케이션에 대한 필요로 인해 다양한 대안책이 나왔습니다.
항목 | Shaded JAR (Uber JAR) |
Spring Boot Executable JAR
|
기본 개념 | 여러 JAR 파일의 내용을 하나의 JAR로 병합 |
애플리케이션과 의존성을 nested JAR 형태로 패키징
|
장점 | 단일 JAR 파일로 배포 가능 |
중첩된 구조로도 문제 없이 실행 가능
|
단점 | - 클래스 이름 충돌 위험 - Reflection 오류 - 디버깅 어려움 |
일반 Java는 중첩 JAR 실행 불가
→ 별도 로더 필요 |
문제 예시 | - 동일한 경로/클래스 이름의 충돌 - 예기치 못한 런타임 오류 발생 가능 |
중첩된 JAR 구조 자체는 문제 없으나, 일반 Java만으로는 실행 불가
|
실행 방법 | 일반 Java로 직접 실행 가능 (java -jar) |
spring-boot-loader가 로드 및 실행 지원
|
핵심 기술/도구 | shading (예: shadow 플러그인) |
spring-boot-loader
|
외부 의존성 처리 방식 | 모든 클래스들을 병합 |
중첩 JAR 형태로 내부에 포함 (예: BOOT-INF/lib)
|
특이 용어 | Uber JAR, Fat JAR |
Loader-Compatible JAR
|
명령어) Spring Boot Executable JAR
더보기
1. 패키징
$ ./gradlew bootJar # build/libs/your-app-1.0.0.jar
2. 실행
java -jar build/libs/your-app-1.0.0.jar
Executable jar File Structure
├── META-INF
│ ├── MANIFEST.MF
│ └── spring.factories
├── BOOT-INF
│ ├── classes
│ │ ├── META-INF
│ │ ├── application.yml
│ │ ├── org
│ │ │ └── ...
│ │ ├── static
│ │ │ └── ...
│ │ └── templates
│ │ └── ...
│ ├── classpath.idx
│ ├── layers.idx
│ └── lib
│ └── ...
├── org
│ └── springframework
│ └── boot
│ └── loader
│ └── ....
항목 | 설명 |
META-INF/ |
JAR 파일의 메타데이터를 포함하는 디렉토리
|
└─ MANIFEST.MF |
JAR의 메타정보가 담긴 파일 (메인 클래스, 클래스패스 등)
|
BOOT-INF/ |
Executable JAR의 핵심 디렉토리.
실행에 필요한 클래스 및 라이브러리 포함 |
└─ classes/ |
사용자가 작성한 클래스 파일들이 컴파일되어 위치함
(예: src/main/java) |
└─ lib/ |
외부 라이브러리 JAR들이 위치 (중첩 JAR)
|
└─ classpath.idx |
lib/ 디렉토리의 클래스패스 정보를 포함
|
└─ layers.idx |
Executable JAR의 계층(layers) 구조 정보를 포함
|
org/springframework/boot/loader/ |
이 구조를 이해하고 실행할 수 있도록 도와주는 로더
|
예시) META-INF
더보기
1. MANIFEST.MF
Manifest-Version: 1.0
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: org.example.Main
Spring-Boot-Version: 3.0.4
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
Spring-Boot-Layers-Index: BOOT-INF/layers.idx
Build-Jdk-Spec: 17
Implementation-Title: spring-boot-document-example
Implementation-Version: 1.0-SNAPSHOT
항목 이름 | 설명 |
Manifest-Version |
MANIFEST 파일의 버전을 나타냅니다.
|
Main-Class |
JAR 파일을 실행할 때 사용되는 기본 진입점 클래스입니다.
Spring Boot에서는 org.springframework.boot.loader.JarLauncher를 사용하여 실행됩니다. |
Start-Class |
실제 애플리케이션의 시작 클래스(메인 클래스)입니다.
Spring Boot가 내부적으로 이 클래스를 찾아 실행합니다. |
Spring-Boot-Version |
현재 프로젝트에서 사용 중인 Spring Boot의 버전입니다. 여기서는 3.0.4입니다.
|
Spring-Boot-Classes |
애플리케이션 클래스 파일들이 위치하는 경로입니다.
|
Spring-Boot-Lib |
JAR 안에 포함된 의존성 라이브러리들이 위치하는 경로입니다.
|
Spring-Boot-Classpath-Index |
클래스패스 인덱스 파일의 위치를 나타냅니다.
JAR 실행 시 클래스 로딩 속도 최적화에 사용됩니다. |
Spring-Boot-Layers-Index |
Layered JAR 구조를 위한 인덱스 파일 경로입니다.
Docker 이미지 빌드시 레이어 캐싱을 효율적으로 할 수 있도록 도와줍니다. |
Build-Jdk-Spec |
이 애플리케이션이 빌드된 JDK의 스펙 버전입니다.
|
Implementation-Title |
애플리케이션의 이름 또는 식별자입니다.
|
Implementation-Version |
애플리케이션의 버전 정보입니다.
|
2. Spring Boot’s “JarFile” Class
항목 | 설명 |
역할 |
Nested JAR 로딩을 담당하는 핵심 클래스
|
기능 | standard JAR 및 nested child JAR를 로드 |
기반 클래스 |
Java 표준 패키지의 클래스를 확장하여 사용
(Java의 핵심 기능을 기반으로 동작) |
로딩 방식 |
처음 로딩 시, 각 JAR 항목은 outer JAR의 offset 값으로 위치 표시
|
데이터 접근 방식 |
offset 기반 접근을 통해 전체를 unpack 하지 않고도 필요 데이터에 접근 가능
|
내부 처리 |
각 항목(파일/클래스)은 JarEntry 객체로 매핑되어 사용됨
|
장점 |
- 효율적인 로딩
- 불필요한 메모리 사용 최소화 - 빠른 실행 속도 |
3. Launching Executable Jars
Launcher
항목 | 설명 |
역할 |
Executable JAR의 진입점(Entry Point) 역할을 하는 특별한 부트스트랩 클래스
|
설정 위치 |
JAR의 MANIFEST.MF 파일에 Main-Class 로 설정됨
|
기능 |
- 적절한 URLClassLoader 설정
- 필요한 리소스를 로딩 - 사용자의 main() 메서드 호출 |
리소스 로딩 |
중첩된 JAR 또는 WAR 디렉토리 내부의 리소스까지 로드 가능
|
로딩 방식 |
각 파일 형식(JAR/WAR)에 따라 서브클래스를 사용하여 적절하게 로딩
|
대표 클래스 예시 |
org.springframework.boot.loader.Launcher (Main-Class로 지정됨)
|
확장 클래스 예시 |
- JarLauncher : JAR 실행용
- WarLauncher : WAR 실행용 등 |
출처