☕️ JAVA/🍃 Spring

Maven Standard Directory Layout과 plain jar, executable jar

kukim 2022. 12. 28. 22:44

이번 글에서는 간략하게 Maven Standard Directory Layout와 plain jar, executable jar에 대해 소개하려 합니다.

 

Maven Standard Directory Layout

흔히 spring boot 프로젝트를 생성하면 아래와 같은 패키지 구조를 가지게 됩니다.

> tree src
src
├── main
│   ├── java
│   │   └── com
│   │       └── kukim
│   │           └── recipe
│   │               └── RecipeApplication.java
│   └── resources
│       ├── application.properties
│       ├── static
│       └── templates
└── test
    └── java
        └── com
            └── kukim
                └── recipe
                    └── RecipeApplicationTests.java

13 directories, 3 files

src/main, src/resources, /src/test ... 와 같은 구조는 어떤 형식을 따르는 것일까요? 왜 이렇게 사용하는 걸까요?

그 이유는 바로 Maven Standard Directory Layout을 따르는 것입니다. 표준 레이아웃을 따르기 때문에 컴파일과 jar 묶을 때 별다른 path 지정 없이 간편하게 빌드 할 수 있습니다. (gradle도 해당 레이아웃을 사용합니다.)

 

plain jar와 executable jar

Spring Boot2.5 이상에서 빌드하면 그 결과로 plain.jar와. jar 파일 두 개가 생성됩니다.

# gradle build
> ./gradlew clean build
BUILD SUCCESSFUL in 5s
8 actionable tasks: 8 executed


# build 결과, build/libs
> ls build/libs
recipe-0.0.1-SNAPSHOT-plain.jar recipe-0.0.1-SNAPSHOT.jar

두 파일의 차이는 무엇일까요?

 

plain.jar

src/main 하위의 컴파일된 소스코드(. class)들과 src/resources 파일들이 묶여있습니다.

이는 외부 의존성(tomcat, jackson, spring-boot)은 존재하지 않습니다. 말 그대로 plain jar이죠.

따라서 plain.jar 만으로는 spring boot를 실행할 수 없습니다.

# plain.jar 압축 해제
> unzip recipe-0.0.1-SNAPSHOT-plain.jar -d plain-jar

# plain.jar 압축 해제한 폴더 tree
> tree plain-jar
plain-jar
├── META-INF
│   └── MANIFEST.MF
├── application.properties
├── com
│   └── kukim
│       └── recipe
│           └── RecipeApplication.class
├── static
└── templates

6 directories, 3 files

 

executable-jar

plain.jar 가 아닌 다른 jar는 executable-jar(실행 가능한 jar)라고 합니다. 개발자가 작성한 소스코드에 추가적으로 외부 의존성이 포함되어 있습니다. 따라서 해당 jar는 내장 톰캣과 여러 의존성을 포함하고 있기 때문에 실행할 수 있게 됩니다.

# executable.jar 압축 해제
> unzip recipe-0.0.1-SNAPSHOT.jar -d plain-jar

# executable-jar 압축 해제한 파일 tree
> tree executable-jar
executable-jar
├── BOOT-INF
│   ├── classes
│   │   ├── application.properties
│   │   ├── com
│   │   │   └── kukim
│   │   │       └── recipe
│   │   │           └── RecipeApplication.class
│   │   ├── static
│   │   └── templates
│   ├── classpath.idx
│   ├── layers.idx
│   └── lib
│       ├── jackson-annotations-2.14.1.jar
│       ├── jackson-core-2.14.1.jar
│       ├── jackson-databind-2.14.1.jar
│       ├── jackson-datatype-jdk8-2.14.1.jar
│       ├── jackson-datatype-jsr310-2.14.1.jar
│       ├── jackson-module-parameter-names-2.14.1.jar
│       ├── jakarta.annotation-api-2.1.1.jar
### 생략

spring boot를 활용하여 jar나 docker image를 생성한다면 executable jar를 가지고 사용하게 됩니다.

+a) 두 파일이 이름이 비슷하게 생기기 때문에 배포 시 *. jar와 같이 경로를 넣게 된다면 executable jar가 아닌 plain jar가 배포되어 실행이 안될 수 있습니다. 이에 유의해야 합니다. gradle의 경우 옵션을 주어 plain 생성되지 않도록 설정할 수 있습니다. (ref : spring boot docs : Packaging Executable and Plain Archives)

 

Reference

- Maven Standard Directory Layout

- spring boot docs : Packaging Executable and Plain Archives