앞날 창창보
article thumbnail

https://blog.naver.com/sbsstyle/222417794297

 

이번에 멀티 모듈을 설정하면서 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 파일을 뜯어보는 것은 이 글을 많이 참고 했습니다!

https://elsboo.tistory.com/27

 

스프링부트 jar 구성 및 실행 원리

maven이나 gradle 같은 빌드 툴로 스프링부트 프로젝트를 빌드하면 하나의 산출물인 jar 파일이 생성된다. 이 jar의 구성은 어떻게 되어있는지, java -jar app.jar 를 하면 application이 어떻게 실행되는지

elsboo.tistory.com

 

 
 
 
 
 

검색 태그