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 실행용 등

 

 

 

출처