기본 Manifest 속성이 없습니다
jar 파일을 빌드해서 실행할 때 Manifest가 없어서 실행이 안된다는 오류가 발생할 수 있습니다. 별다른 설정이 없다면 실행가능한 jar 대신에 실행가능하지 않은 jar를 생성하기 때문입니다.
원인은 빌드된 jar 바이너리 안에 MANIFEST.MF 파일이 없기 때문이며 이 파일은 jar의 메타데이터를 포함하고 있는 파일로서 가장 중요한 용도는 main() 메소드를 포함하는 클래스의 위치(엔트리 포인트)를 지정하는 것입니다.
이런 에러가 발생하지 않고 제대로 실행되는 jar를 "실행가능한 jar"라고 부르는데, 실행가능한 jar를 만드는 주요한 방법들을 몇 가지 살펴보겠습니다. 원리 이해에는 별 관심없고 간단한 해결방법을 찾는 분은 3번이나 4번 단락을 읽어보시기 바랍니다.
jar 명령의 -e 옵션을 이용하면 엔트리 포인트를 지정하기 때문에 MANIFEST.MF 파일이 없어도 실행 가능한 jar를 만들 수 있습니다.
jar -cfe my_app.jar Main *.class
java -jar my_app.jar
그러나 이 방법은 여러 가지 한계점을 가지고 있는데, 의존하는 외부 라이브러리가 많거나 maven을 이용해서 빌드하는 경우에는 쉽게 사용할 수 있는 방법이 아닙니다.
IntelliJ에서는 다음의 과정을 통해 artifact(jar 바이너리)를 만드는 게 좋습니다.
maven의 여러가지 표준 플러그인으로 실행 가능한 jar를 만들 수 있습니다.
참고: https://www.baeldung.com/executable-jar-with-maven
이중에서 가장 간단한 방법은 assembly 플러그인을 사용하는 방법인데, 다음과 같은 설정을 pom.xml에 추가하면 간단하게 해결됩니다. 생성되는 아티팩트의 이름에 with-dependencies라는 접미어가 붙습니다. Main 클래스의 이름을 정확하게 적어주어야 엔트리 포인트로서 동작합니다.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>
com.terzeron.spring.Main
</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
요즘은 assembly 플러그인 대신에 좀 더 커스터마이즈가 가능한 shade 플러그인을 쓰는 방법이 선호되고 있습니다. (Spring batch 프로젝트에서 CommandLineJobRunner 애플리케이션을 만드는 경우에는 assembly는 어렵고 shade 플러그인으로 설정을 하는 게 편리합니다.)
다음과 같은 설정을 pom.xml에 추가하면 됩니다. 마찬가지로 Main 클래스을 정확히 지정해야 합니다.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>
com.terzeron.spring.Main
</mainClass>
</transformer>
</transformers>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
maven-jar-plugin이 jar를 만들면, 외부 의존성이 없고 내부 코드를 컴파일해서 그냥 묶어두기만한 파일입니다. 반면에, spring-boot-maven-plugin
이 repackage하면서 외부 의존성을 포함시키고 실행 가능한 jar 파일을 만들 수 있습니다.
pom.xml에 spring-boot-maven-plugin 설정을 추가합니다.
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
독립 실행 가능한(self executable or fully executable) jar를 만드는 방법도 있습니다.
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
</plugins>
</build>