uber-jar 를 만들기 위한 maven shade plugin
소개
의존성을 포함한 실행 가능한 single jar(이하 uber-jar) 파일을 생성해 주는 플러그인. maven assembly plugin 대신 shade plugin 사용하는게 좋음.
uber-jar 의미
사용
실행 가능 jar 만들기
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.0.0</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>org.sonatype.haven.HavenCli</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin>
실행 가능한 jar 를 만들기 위해 transformer 에 mainClass 를 설정
Spring app
spring 을 사용한 console app 를 shade 플러그인을 사용하여 uber jar 로 생성하는 예제.
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.0.0</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.example.app.MinimalSpringApp</mainClass> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.handlers</resource> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.schemas</resource> </transformer> </transformers> </configuration> </execution> </executions> </plugin>
만약 assembly plugin 으로 single jar 파일을 만들면 다음과 같이 spring xml 스키마를 찾지 못하는 예외 발생
Exception in thread "main" org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/context] Offending resource: URL [jar:file:/home/lesstif/proj/target/proj-0.0.1-SNAPSHOT-jar-with-dependencies.jar!/application-config.xml] at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68)
“Invalid signature file” 해결
manifesto 가 있는 jar 파일의 경우 shade 플러그인으로 묶을 때 다음과 같은 에러가 발생할 수 있음
Exception in thread "main" java.lang.SecurityException: Invalid signature file digest for Manifest main attributes
manifest signature 를 제외하는 내용 추가
<configuration> <filters> <filter> <artifact>*:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> <!-- Additional configuration. --> </configuration>
junit 까지 포함하여 jar 만들기
junit 테스트 케이스가 포함된 jar 를 만들고 싶은 경우 junit.jar를 포함해서 최종 jar 를 생성해야 한다. <configuration> 항목에 filters 로 포함할 패키지와 제외할 패키지를 설정할 수 있다.
<configuration> <filters> <filter> <artifact>junit:junit</artifact> <includes> <include>junit/**</include> <include>org/junit/**</include> </includes> </filter> <filter> <artifact>org.hamcrest:hamcrest-all</artifact> <includes> <include>org/hamcrest/**</include> <include>com/thoughtworks//**</include> </includes> </filter> <filter> <artifact>*:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> </configuration>
<dependency> 설정에서 junit 의 scope 이 <test> 면 포함되지 않으므로 <scope>test</scope> 항목을 주석 처리해야 한다.
생성한 uber-jar 는 다음과 같이 junit 테스트 케이스를 바로 실행할 수 있다. (TestCase 는 실행할 junit 테스트)
java -cp target/myproj-1.0.1.jar org.junit.runner.JUnitCore TestCase
Ref
- http://maven.apache.org/plugins/maven-shade-plugin/
- http://stackoverflow.com/questions/11947037/what-is-an-uber-jar/11947093#11947093
- http://stackoverflow.com/questions/15110671/unable-to-locate-spring-namespacehandler-error
- http://stackoverflow.com/questions/999489/invalid-signature-file-when-attempting-to-run-a-jar/6743609#6743609