이 글은 다음의 글을 내 맘대로 번역한 글입니다
www.baeldung.com/spring-boot-repackage-vs-mvn-package
Difference Between spring-boot:repackage and Maven package | Baeldung
Learn the difference between mvn:package and spring-boot:repackage
www.baeldung.com
1. Overview
Apach Maven은 널리 사용되는 프로젝트 의존성 관리 tool이자 project building tool이다. 지난 몇 년간 Spring Boot는 application 개발을 위한 아주 인기가 많은 프레임워크가 되었다. Spring boot Maven Plugin이 있는데 Maven에서 Spring Boot supoort를 제공한다
application을 JAR or WAR artifact 형태로 Maven 을 이용해서 패키징하고 싶은 때가 있다. 이 때 mvn package를 사용하면 된다. 하지만 Spring Boot Maven Plugin은 repackage goal로 출고되는데 mvn command라고 한다.
가끔 두개의 명령어가 혼란스럽다. 이번 toturial에서는 mvn pckage와 spring-boot:repackage의 차이점에 대해서 설명한다
2. A Spring Boot Application Example
맨 처음 바로 Spring Boot application 을 만든다
@SpringBootApplication
public class SpringBootArtifacts2Application {
public static void main(String[] args) {
SpringApplication.run(SpringBootArtifacts2Application.class, args);
}
}
그리고 application이 빌드되고 기동된다는 것을 검증하기 위해 간단한 REST endpoint를 생성한다
@RestController
public class DemoRestController {
@GetMapping(value = "/welcome")
public ResponseEntity welcomeEndpoint() {
return ResponseEntity.ok("Welcome to Baeldung Spring Boot Demo!");
}
}
3. Maven package Goal
Spring Boot application을 빌드하려면 spring-boot-starter-web 의존성만 있으면된다.
<artifactId>spring-boot-artifacts-2</artifactId>
<packaging>jar</packaging>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
...
하지만 STS를 이용해서 Spring Boot 프로젝트를 선택하면 아래처럼 maven-plugin도 자동으로 적용된다. 일단 이부분은 주석처리를 하고 실행한다
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Maven's package goal은 코드를 컴파일하고 패키징한다. 이 예제에서는 JAR format이다
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------< com.example:spring-boot-artifacts-2 >-----------------
[INFO] Building spring-boot-artifacts-2 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ spring-boot-artifacts-2 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Using 'UTF-8' encoding to copy filtered properties files.
[INFO] Copying 1 resource
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ spring-boot-artifacts-2 ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:3.2.0:testResources (default-testResources) @ spring-boot-artifacts-2 ---
[INFO] Not copying test resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ spring-boot-artifacts-2 ---
[INFO] Not compiling test sources
[INFO]
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ spring-boot-artifacts-2 ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ spring-boot-artifacts-2 ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.016 s
[INFO] Finished at: 2021-02-03T01:14:27+09:00
[INFO] ------------------------------------------------------------------------
mvn package 명령어를 실행하고 나면 jar 파일이 생성된 것을 확인할 수 있고 JAR 파일 내부를 살펴보자
위 사진에서 볼 수 있듯이 mvn package 명령어의 결과로 JAR 파일이 만들어졌고 내부에는 resources와 컴파일된 Java class만이 포함되어 있다
실행에 필요한 libs도 없다.
이 JAR 파일을 이용해서 다른 프로젝트에 의존성으로 사용할 수도 있다. 하지만 Spring Boot application이면 이 JAR파일을 "java -jar JAR_FILE" 명령어를 이용해서 기동시키지 못한다. runtime 의존성이 포함되어 있지 않기 때문이다. 예를 들자면 web context를 기동시킬 수 있는 servlet container가 없다.
"java -jar" 명령어를 이용해서 간단하게 실행시킬려면 fat JAR이 필요하다. 이것을 만들기 위해 Spring Boot Maven Plugin이 필요하다
4. The Spring Boot Maven Plugin's repackage Goal
spring-boot:repackage가 무엇을 하는지 알아보자
4.1 Spring Boot Maven Plugin 추가하기
이미 위에서 설명했듯이 기본적으로 적용되어 있다.
4.2 spring-boot:repackage Goal 실행
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------< com.example:spring-boot-artifacts-2 >-----------------
[INFO] Building spring-boot-artifacts-2 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ spring-boot-artifacts-2 ---
[INFO] Deleting D:\workspaces\git\spring-boot-artifacts-2\target
[INFO]
[INFO] --- spring-boot-maven-plugin:2.4.2:repackage (default-cli) @ spring-boot-artifacts-2 ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.193 s
[INFO] Finished at: 2021-02-03T01:35:19+09:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.4.2:repackage (default-cli) on project spring-boot-artifacts-2: Execution default-cli of goal org.springframework.boot:spring-boot-maven-plugin:2.4.2:repackage failed: Source file must not be null -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginExecutionException
실패했다. 왜냐하면 spring-boot:repackage goal은 존재하는 JAR or WAR archive를 입력소스로 취하고 project runtime 의존성을 전부 final artifact내에 재패키징한다. 이런 방법으로 재패키징 된 artifact는 "java -jar JAR_FILE.jar" 명령어로 실행이 가능하다
따라서 먼저 JAR 파일을 만들고 그 후에 spring-boot:repackage goal을 실행해야 한다
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------< com.example:spring-boot-artifacts-2 >-----------------
[INFO] Building spring-boot-artifacts-2 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ spring-boot-artifacts-2 ---
[INFO] Deleting D:\workspaces\git\spring-boot-artifacts-2\target
[INFO]
[INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ spring-boot-artifacts-2 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Using 'UTF-8' encoding to copy filtered properties files.
[INFO] Copying 1 resource
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ spring-boot-artifacts-2 ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 2 source files to D:\workspaces\git\spring-boot-artifacts-2\target\classes
[INFO]
[INFO] --- maven-resources-plugin:3.2.0:testResources (default-testResources) @ spring-boot-artifacts-2 ---
[INFO] Not copying test resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ spring-boot-artifacts-2 ---
[INFO] Not compiling test sources
[INFO]
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ spring-boot-artifacts-2 ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ spring-boot-artifacts-2 ---
[INFO] Building jar: D:\workspaces\git\spring-boot-artifacts-2\target\spring-boot-artifacts-2-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- spring-boot-maven-plugin:2.4.2:repackage (repackage) @ spring-boot-artifacts-2 ---
[INFO] Replacing main artifact with repackaged archive
[INFO]
[INFO] --- spring-boot-maven-plugin:2.4.2:repackage (default-cli) @ spring-boot-artifacts-2 ---
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.056 s
[INFO] Finished at: 2021-02-03T01:41:21+09:00
[INFO] ------------------------------------------------------------------------
아래 그림에서 볼 수 있듯이 original JAR file과 repackaged JAR file을 볼 수 있다.
JAR 파일 내부를 살펴보자
repackaged JAR 파일을 보면 컴파일된 Java classes와 Spring Boot application을 실행하는데 필요한 모든 runtime libraries 가 모두 포함되어 있다. 예를 들어, embedded tomcat library는 BOOT-INF/lib directory에 패키징되어 있다
4.3 Maven's package Lifecycle동안 spring-boot:repackage Goal 실행하기
pom.xml에서 Maven lifecycle의 package phase동안 Spring Boot Maven Plugin이 artifact를 재패키징한다는 것을 안다. 다른 말로하면 mvn package를 실행하면 spring-boot:repackage가 자동으로 실행된다다는 것이다