Jar
1 Jar
- Jar (Java Archive) 파일은 여러 Java 클래스 파일과 관련 메타데이터, 리소스(텍스트, 이미지 등)를 하나의 파일로 묶어 배포하기 위한 패키지 파일 형식입니다.
- 이러한 파일들은 주로 Java 애플리케이션 또는 라이브러리를 배포하는 데 사용됩니다.
- Jar 파일은 ZIP 형식으로 생성되 며 .jar 파일 확장자를 가집니다.
- 컴파일된 Java 클래스 및 관련 리소스를 저장하는 데 사용되어 Java 소프트웨어 또는 라이브러리의 배포 및 배포를 용이하게 합니다.
1.1 작동 방식
- 컴파일
- Java 소스 파일(.java)은 Java 컴파일러에 의해 바이트코드(.class 파일)로 컴파일됩니다.
- 패키징
- 이러한 클래스 파일과 관련 리소스는 단일 Jar 파일로 함께 패키징됩니다.
- 여기에는 구성 데이터 및 애플리케이션 진입점을 지정할 수 있는 매니페스트 파일(MANIFEST.MF)과 같은 파일에 대한 메타데이터가 포함될 수 있습니다.
- 실행
- Jar 파일에 애플리케이션의 진입점(메인 클래스)을 지정하는 매니페스트가 포함되어 있는 경우 JRE(Java Runtime Environment)에서 실행할 수 있습니다.
java -jar myapplication.jar명령은 실행 가능한 Jar 파일을 실행하는 데 사용됩니다.
2 Jar의 종류
2.1 Plain Jar
- Plain Jar는 기본적인 Jar 파일로, 프로젝트의 컴파일된 클래스 파일과 리소스만을 포함합니다.
- 이는 외부 라이브러리나 종속성은 포함하지 않습니다.
- Plain Jar는 다른 프로젝트에서 라이브러리로 사용되거나, 클래스패스에 추가되어 사용될 수 있습니다.
- 하지만 Plain Jar 자체만으로는 실행할 수 없으며, 필요한 종속성을 별도로 제공해야 합니다.
- WAR와 다르게 JAR 파일은 내부에 라이브러리 역할을 하는 JAR 파일을 포함할 수 없습니다.
- jar를 포함시켜도 인식되지 않습니다.
- 이것이 JAR 파일 스펙의 한계이며 이를 해결하기 위해 Fat Jar를 사용합니다.
2.2 Fat Jar (Uber Jar)
- Fat Jar 또는 Uber Jar로도 불리는 이 파일은 애플리케이션을 실행하는 데 필요한 모든 종속성과 리소스를 포함하는 Jar 파일입니다.
- 즉, 프로젝트에서 사용된 모든 외부 라이브러리 파일이 Fat Jar에 포함되어 있어, 이 Jar 파일만으로 애플리케이션을 실행할 수 있습니다.
- jar안에는 jar를 포함시켜도 인식되지 않습니다. 그러나 클래스는 얼마든지 포함시킬 수 있습니다.
- fat jar는 라이브러리에 사용되는 jar를 풀어 나오는 class를 뽑아 새로운 jar에 포함시는 방식으로 jar를 생성합니다. 그래서 fat jar라고 부릅니다.
2.2.1 장점
- Fat Jar 덕분에 하나의 jar 파일에 필요한 라이브러리들을 내장할 수 있게 되었습니다.
- 내장 톰캣 라이브러리를 jar 내부에 내장하 여 하나의 jar 파일로 배포부터, 웹 서버 설치, 실행까지 모든 것을 단순화 할 수도 있습니다.
2.2.2 단점
- 이는 배포 과정을 단순화하지만 파일 크기가 증가하는 단점이 있습니다.
- 어떤 라이브러리가 포함되어 있는지 확인하기 어렵습니다.
- 모든 class 파일을 풀어 어떤 라이브러리가 사용되고 있는지 추적하기 어렵습니다.
- 파일명 중복을 피할 수 없습니다.
- 서로 다른 라이브러리에서 클래스나 리소스 명이 중복되는 경우 하나만 선택하고 나머지는 포기해야 합니다.
2.3 Boot Jar (실행 가능 Jar)
- Boot Jar는 Spring Boot 프레임워크에서 사용되는 특수한 유형의 Jar 파일입니다.
- 이는 Fat Jar의 개념을 확장하며 Spring Boot 애플리케이션을 실행하는 데 필요한 모든 것을 포함합니다.
- Boot Jar는 Spring Boot의 특정 구조를 따르며 내장 컨테이너(예: Tomcat)를 사용하여 웹 애플리케이션을 쉽게 배포하고 실행하기 위해 설계되었습니다.
2.3.1 실행 가능 Jar의 필요성
- Spring Boot는 Fat Jar의 문제점을 해결하기 위해 jar 내부에 jar를 포함할 수 있는 특별한 구조의 jar를 만들었습니다.
- 이를 실행 가능 Jar(Executable Jar)라 하며, 다음과 같은 문제들을 해결합니다.
- 라이브러리 식별 문제: jar 내부에 jar를 포함하기 때문에 어떤 라이브러리가 포함되어 있는지 쉽게 확인할 수 있습니다.
- 파일명 중복 문제:
a.jar,b.jar내부에 같은 경로의 파일이 있어도 둘 다 인식할 수 있습니다.
노트
실행 가능 Jar는 자바 표준이 아니라 Spring Boot에서 새롭게 정의한 것입니다.
2.3.2 Boot Jar 내부 구조
Boot Jar는 다음과 같은 구조를 가집니다:
boot-0.0.1-SNAPSHOT.jar
├── META-INF/
│ └── MANIFEST.MF
├── org/springframework/boot/loader/
│ └── JarLauncher.class (Spring Boot main() 실행 클래스)
└── BOOT-INF/
├── classes/ (개발한 class 파일과 리소스 파일)
│ ├── hello/boot/BootApplication.class
│ └── hello/boot/controller/HelloController.class
├── lib/ (외부 라이브러리)
│ ├── spring-webmvc-6.0.4.jar
│ └── tomcat-embed-core-10.1.5.jar
├── classpath.idx (외부 라이브러리 모음)
└── layers.idx (Spring Boot 구조 정보)
2.3.3 MANIFEST.MF 파일 구조
java -jar xxx.jar 실행 시 META-INF/MANIFEST.MF 파일을 읽어 실행 정보를 확인합니다:
Manifest-Version: 1.0
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: hello.boot.BootApplication
Spring-Boot-Version: 3.0.2
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
- Main-Class
- 실제 실행되는 클래스는
JarLauncher입니다 (우리가 작성한 메인 클래스가 아님) - 스프링 부트가 빌드 시 Main-Class에
JarLauncher를 등록합니다. - 특별한 장치 없이는 jar안에는 jar를 넣을 수 없습니다.
JarLauncher가 jar 내부에서 jar를 읽어들이는 기능을 합니다. 이 작업을 진행한 후에 Start-Class에 지정된 main()을 호출하게 됩니다.
- 실제 실행되는 클래스는
- Start-Class: 우리가 작성한 실제 애플리케이션의 메인 클래스입니다
- 기타 항목들: Spring Boot가 내부에서 사용하는 정보들입니다
경고
Main-Class를 제외한 나머지는 자바 표준이 아니라 Spring Boot가 임의로 사용하는 정보입니다.
2.3.4 Spring Boot 로더
org/springframework/boot/loader하위에 있는 클래스들입니다.JarLauncher를 포함한 Spring Boot가 제공하는 실행 가능 Jar를 실제로 구동시키는 클래스들이 포함되어 있습니다.- Spring Boot는 빌드 시에 이 클래스들을 포함해서 Boot Jar를 만들어줍니다.
2.3.5 BOOT-INF 구조
- classes: 개발한 class 파일과 리소스 파일
- lib: 외부 라이브러리 jar 파일들
- classpath.idx: 외부 라이브러리 목록
- layers.idx: Spring Boot 구조 정보
팁
WAR 구조의 WEB-INF와 유사한 개념으로, BOOT-INF라는 이름을 사용합니다.
2.3.6 실행 과정
Boot Jar의 실행 과정은 다음과 같습니다:
java -jar xxx.jar명령어 실행MANIFEST.MF파일 인식JarLauncher.main()실행BOOT-INF/classes/인식BOOT-INF/lib/인식
BootApplication.main()실행 (실제 애플리케이션 시작)
정보
IDE에서 직접 실행할 때는 BootApplication.main()을 바로 실행합니다. IDE가 필요한 라이브러리를 모두 인식할 수 있게 도와주기 때문에 JarLauncher가 필요하지 않습니다.