본문 바로가기
☕️ JAVA/🍃 Spring

Maven Standard Directory Layout과 plain jar, executable jar

by kukim 2022. 12. 28.

이번 글에서는 간략하게 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

댓글