이번에 멀티 모듈을 설정하면서 gradle에 처음으로 bootJar와 Jar 설정을 건드려봤다.
깨달은 점은 의존 당할 모듈에서는 jar 설정만 true로 하여서, plain-jar가 생성되게 하고, 최상단에서 Application 파일을 가지고 있고. 실행될 모듈은 bootjar만 필요로 한다는 것이었다.
이번 블로그에서는 bootJar와 jar의 차이, jar 파일과 plain-jar 파일의 차이를 다룬다.
bootJar와 Jar 설정에 대한 결과
설정에 대한 결과를 알아보기 전 설정 방법을 간단하게 알아보자면, 아래와 같은 설정을 적용하고 싶은 모듈의 gradle 파일에 넣으면 된다.
bootJar {
enabled = false // bootJar 설정을 false로 한 것입니다.
}
jar {
enabled = true // jar 설정을 false로 한 것입니다.
}
만약 bootJar를 true로 했다면
다음과 같이 /build/libs 의 경로에 모듈명.jar 파일(executable jar)이 생기게 된다.
그리고 만약 jar를 true로 했다면
다음과 같이 /build/libs 의 경로에 모듈명-plain.jar 파일이 생기게 된다.
.jar 파일과 plain.jar 파일은 각자 뭘 위해서 만들어질까?
각각의 파일을 압축을 해제한 후 비교해보자. 압축을 해제하는 명령어는 "jar xvf 파일명.jar"이다.
excutable jar 파일의 내부 구조
.
├── jar
│ ├── BOOT-INF
│ │ ├── classes // 개발한 class 파일과 yml 파일 등 template 파일이 존재
│ │ ├── classpath.idx // 스프링 부트가 lib에 있는 외부라이브러리를 찾을 수 있도록 classpath를 정리해둠
│ │ ├── layers.idx // 도커에서 이미지를 만들 때 사용하는
│ │ └── lib
│ ├── META-INF
│ │ ├── BOOT.SF
│ │ ├── MANIFEST.MF
│ │ └── services
│ └── org
│ └── springframework
각각의 파일 혹은 디렉토리를 알아보겠다.
1. BOOT-INF: 개발한 소스 코드가 들어가있는 영역
- class: 개발한 class 파일과 yml 파일 등 template 파일이 존재하는 디렉토리
- classpath.idx: 스프링 부트가 lib에 있는 외부 라이브러리를 찾을 수 있도록 classpath를 정리해둔 파일
- layers.idx: 도커에서 각각의 외부 라이브러리를 레이어로 가져오기 위해서 정리해둔 파일
- lib: 사용하는 외부 라이브러리를 jar 파일로 저장해둔 디렉토리
2. org/springframework/boot/loader: 스프링부트 영역
- 기본 java에서 제공하는 jar 파일을 실행하는 클래스를 사용하지 않고, spring-boot-loarder를 통해서 실행하는 이유는 자바는 jar안의 jar(=nested)를 로드하는 방식을 제공하지 않아서. 자신만의 방식으로 로드하는 것이다.
3. META-INF: 스프링부트와 우리가 개발한 소스 코드를 연결해주는영역
- MANIFEST.MF: jar가 실행되면 가장 먼저 Main-class인 JarLauncher가 호출되는데, JarLauncher에서 우리가 개발한 Start-Class를 호출하기 위해서 존재하는 파일
- BOOT.SF: 비어있는 파일이고, 구글링을 했을 때, 잘 나오지 않아서 역할을 모르겠다. 이름이 BOOT인 것으로 미루어보아 실행과 관련된 파일인 것 같다.
- service:
다음의 파일안에 이름과 똑같은 문자가 들어가있다. nio란 java4 버전에 추가된 새로운 IO(New IO)이다. 파일 시스템을 설정하기 위해서 정의된 파일같다.
plain jar의 내부 구조
└── plain-jar
├── META-INF
│ └── MANIFEST.MF
├── application.yml
├── com
│ └── sickgyun
└── templates
├── WantedSansVariable.woff2
├── accept-mail.html
├── application-mail.html
├── cancelled-mail.html
└── reject-mail.html
내가 작성한 코드와, 스프링 부트와 연결에주는 MANIFEST.MF 파일만 있는 것을 확인할 수 있다.
두 jar파일의 MANIFEST.MF를 비교해보면
//excutable jar
Manifest-Version: 1.0
Main-Class: org.springframework.boot.loader.launch.JarLauncher
Start-Class: com.sickgyun.server.ServerApplication
Spring-Boot-Version: 3.2.1
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: 21
Implementation-Title: main-service
//plain-jar
Manifest-Version: 1.0
plain-jar는 Manifest의 버전 정보만 담고 있는 것을 알 수 있다. 그렇기에 plain-jar 파일 단독으로 실행할 수 없다.
다음과 같은 이유로 실제로 실행되는 모듈은 jar파일만 필요로 하는 것이고, 바로 실행되지 않는 모듈을 plain-jar를 필요로 하는 것이다.
궁금한 것...은 jar에서 plain-jar를 가져올 때, 어떻게 plain-jar에서 사용하는 dependency들을 알고 가져오는 것이다. 알면 댓글로 알려주세요 ㅠㅠ
jar 파일을 뜯어보는 것은 이 글을 많이 참고 했습니다!
'기술고민' 카테고리의 다른 글
모듈은 어떤 상황에서 분리되어야 할까? (0) | 2024.04.21 |
---|---|
Fixture Monkey를 써야 할까? (0) | 2024.04.16 |
스프링 시큐리티를 쓰지 맙시다. (feat. JWT) (4) | 2024.04.13 |
SonarCloud, Qodana 둘중 무엇을 골라야할까? (1) | 2024.04.05 |
int와 Integer중에 무엇을 골라야할까? (4) | 2024.03.28 |