[java] Maven을 사용하여 종속성이있는 실행 가능한 JAR을 어떻게 만들 수 있습니까?

배포를 위해 프로젝트를 단일 실행 가능한 JAR로 패키지하고 싶습니다.

Maven 프로젝트 패키지를 모든 종속성 JAR을 출력 JAR로 만드는 방법은 무엇입니까?



답변

<build>
  <plugins>
    <plugin>
      <artifactId>maven-assembly-plugin</artifactId>
      <configuration>
        <archive>
          <manifest>
            <mainClass>fully.qualified.MainClass</mainClass>
          </manifest>
        </archive>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
      </configuration>
    </plugin>
  </plugins>
</build>

그리고 당신은 그것을 실행

mvn clean compile assembly:single

컴파일 목표는 어셈블리 전에 추가해야합니다 : 단일 또는 그렇지 않으면 자신의 프로젝트 코드가 포함되지 않습니다.

주석에서 자세한 내용을 참조하십시오.


일반적으로이 목표는 빌드 단계와 연결되어 자동으로 실행됩니다. 이를 통해 mvn install배치 / 릴리스를 실행 하거나 수행 할 때 JAR이 빌드됩니다 .

<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <mainClass>fully.qualified.MainClass</mainClass>
      </manifest>
    </archive>
    <descriptorRefs>
      <descriptorRef>jar-with-dependencies</descriptorRef>
    </descriptorRefs>
  </configuration>
  <executions>
    <execution>
      <id>make-assembly</id> <!-- this is used for inheritance merges -->
      <phase>package</phase> <!-- bind to the packaging phase -->
      <goals>
        <goal>single</goal>
      </goals>
    </execution>
  </executions>
</plugin>


답변

dependency-plugin을 사용하여 패키지 단계 전에 별도의 디렉토리에 모든 종속성을 생성 한 후 매니페스트의 클래스 경로에 포함시킬 수 있습니다.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>${project.build.directory}/lib</outputDirectory>
                <overWriteReleases>false</overWriteReleases>
                <overWriteSnapshots>false</overWriteSnapshots>
                <overWriteIfNewer>true</overWriteIfNewer>
            </configuration>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <classpathPrefix>lib/</classpathPrefix>
                <mainClass>theMainClass</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>

또는 ${project.build.directory}/classes/lib모든 jar 파일을 기본 jar에 통합하기 위해 OutputDirectory로 사용 하십시오. 그러나 jar를로드하려면 사용자 정의 클래스 로딩 코드를 추가해야합니다.


답변

나는 이것을하는 몇 가지 다른 방법에 대해 블로그했습니다.

Apache Maven으로 실행 가능한 Jar 참조 (WordPress)이 포함 된

또는 실행 가능한 jar-with-maven-example (GitHub)

노트

이러한 장단점은 Stephan에서 제공합니다 .


수동 배포

  • 찬성
  • 단점
    • 종속성은 최종 병에서 벗어났습니다.

특정 디렉토리에 종속성 복사

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-dependency-plugin</artifactId>
  <executions>
    <execution>
      <id>copy-dependencies</id>
      <phase>prepare-package</phase>
      <goals>
        <goal>copy-dependencies</goal>
      </goals>
      <configuration>
        <outputDirectory>${project.build.directory}/${project.build.finalName}.lib</outputDirectory>
      </configuration>
    </execution>
  </executions>
</plugin>

Jar 실행 파일과 클래스 경로 인식

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-jar-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <addClasspath>true</addClasspath>
        <classpathPrefix>${project.build.finalName}.lib/</classpathPrefix>
        <mainClass>${fully.qualified.main.class}</mainClass>
      </manifest>
    </archive>
  </configuration>
</plugin>

이 시점에서 jar실제로는 외부 클래스 경로 요소로 실행 가능합니다.

$ java -jar target/${project.build.finalName}.jar

배포 가능한 아카이브 만들기

jar파일은 형제 ...lib/디렉토리 에서만 실행할 수 있습니다. 디렉토리와 그 내용으로 배포 할 아카이브를 만들어야합니다.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-antrun-plugin</artifactId>
  <executions>
    <execution>
      <id>antrun-archive</id>
      <phase>package</phase>
      <goals>
        <goal>run</goal>
      </goals>
      <configuration>
        <target>
          <property name="final.name" value="${project.build.directory}/${project.build.finalName}"/>
          <property name="archive.includes" value="${project.build.finalName}.${project.packaging} ${project.build.finalName}.lib/*"/>
          <property name="tar.destfile" value="${final.name}.tar"/>
          <zip basedir="${project.build.directory}" destfile="${final.name}.zip" includes="${archive.includes}" />
          <tar basedir="${project.build.directory}" destfile="${tar.destfile}" includes="${archive.includes}" />
          <gzip src="${tar.destfile}" destfile="${tar.destfile}.gz" />
          <bzip2 src="${tar.destfile}" destfile="${tar.destfile}.bz2" />
        </target>
      </configuration>
    </execution>
  </executions>
</plugin>

이제 당신은 target/${project.build.finalName}.(zip|tar|tar.bz2|tar.gz)각각 포함하는 jarlib/*.


아파치 메이븐 어셈블리 플러그인

  • 찬성
  • 단점
    • 클래스 재배치가 지원되지 않습니다 (클래스 재배치가 필요한 경우 maven-shade-plugin 사용).
<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>${fully.qualified.main.class}</mainClass>
          </manifest>
        </archive>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
      </configuration>
    </execution>
  </executions>
</plugin>

당신은 있습니다 target/${project.bulid.finalName}-jar-with-dependencies.jar.


Apache Maven Shade 플러그인

  • 찬성
  • 단점
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <executions>
    <execution>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <shadedArtifactAttached>true</shadedArtifactAttached>
        <transformers>
          <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <mainClass>${fully.qualified.main.class}</mainClass>
          </transformer>
        </transformers>
      </configuration>
    </execution>
  </executions>
</plugin>

당신은 있습니다 target/${project.build.finalName}-shaded.jar.


onejar-maven-plugin

  • 찬성
  • 단점
    • 2012 년부터 적극적으로 지원되지 않습니다.
<plugin>
  <!--groupId>org.dstovall</groupId--> <!-- not available on the central -->
  <groupId>com.jolira</groupId>
  <artifactId>onejar-maven-plugin</artifactId>
  <executions>
    <execution>
      <configuration>
        <mainClass>${fully.qualified.main.class}</mainClass>
        <attachToBuild>true</attachToBuild>
        <!-- https://code.google.com/p/onejar-maven-plugin/issues/detail?id=8 -->
        <!--classifier>onejar</classifier-->
        <filename>${project.build.finalName}-onejar.${project.packaging}</filename>
      </configuration>
      <goals>
        <goal>one-jar</goal>
      </goals>
    </execution>
  </executions>
</plugin>

스프링 부트 메이븐 플러그인

  • 찬성
  • 단점
    • 불필요한 스프링 및 스프링 부트 관련 클래스를 추가하십시오.
<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <executions>
    <execution>
      <goals>
        <goal>repackage</goal>
      </goals>
      <configuration>
        <classifier>spring-boot</classifier>
        <mainClass>${fully.qualified.main.class}</mainClass>
      </configuration>
    </execution>
  </executions>
</plugin>

당신은 있습니다 target/${project.bulid.finalName}-spring-boot.jar.


답변

Unanswered의 답변을 받아 다시 포맷하면 다음과 같은 이점이 있습니다.

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>fully.qualified.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
        </plugin>
    </plugins>
</build>

다음으로, 명시 적으로 호출하는 것이 아니라 자연스럽게 빌드의 일부로 만드는 것이 좋습니다. 이것을 빌드의 필수 부분으로 만들려면이 플러그인을 추가 pom.xml하고 package라이프 사이클 이벤트에 바인딩하십시오 . 그러나 assembly:single이것을 pom.xml에 넣으면 목표 를 호출해야하지만 명령 줄에서 수동으로 실행하면 ‘assembly : assembly’를 호출해야합니다.

<project>
  [...]
  <build>
      <plugins>
          <plugin>
              <artifactId>maven-assembly-plugin</artifactId>
              <configuration>
                  <archive>
                      <manifest>
                          <addClasspath>true</addClasspath>
                          <mainClass>fully.qualified.MainClass</mainClass>
                      </manifest>
                  </archive>
                  <descriptorRefs>
                      <descriptorRef>jar-with-dependencies</descriptorRef>
                  </descriptorRefs>
              </configuration>
              <executions>
                  <execution>
                      <id>make-my-jar-with-dependencies</id>
                      <phase>package</phase>
                      <goals>
                          <goal>single</goal>
                      </goals>
                  </execution>
              </executions>
          </plugin>
      [...]
      </plugins>
    [...]
  </build>
</project>


답변

maven-shade-plugin을 사용하여 모든 종속성을 하나의 uber-jar로 패키지하십시오. 기본 클래스를 지정하여 실행 가능 jar을 빌드하는 데 사용될 수도 있습니다. maven-assembly 및 maven-jar을 사용하려고 시도한 후이 플러그인이 내 요구에 가장 적합하다는 것을 알았습니다.

이 플러그인은 특정 파일의 내용을 덮어 쓰지 않고 병합하므로 특히 유용합니다. jar에 동일한 이름의 자원 파일이 있고 플러그인이 모든 자원 파일을 패키지하려고 할 때 필요합니다.

아래 예를 참조하십시오

      <plugins>
    <!-- This plugin provides the capability to package the artifact in an uber-jar, including its dependencies and to shade - i.e. rename - the packages of some of the dependencies. -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>1.4</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <artifactSet>
                        <!-- signed jars-->
                            <excludes>
                                <exclude>bouncycastle:bcprov-jdk15</exclude>
                            </excludes>
                        </artifactSet>

                         <transformers>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <!-- Main class -->
                                <mainClass>com.main.MyMainClass</mainClass>
                            </transformer>
                            <!-- Use resource transformers to prevent file overwrites -->
                            <transformer
                                 implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                <resource>properties.properties</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                                <resource>applicationContext.xml</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                <resource>META-INF/cxf/cxf.extension</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                                <resource>META-INF/cxf/bus-extensions.xml</resource>
                            </transformer>
                     </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>

    </plugins>


답변

오랫동안 maven 어셈블리 플러그인 을 사용했지만 문제에 대한 해결책을 찾지 못했습니다 "already added, skipping". 이제 다른 플러그인 인 onejar-maven-plugin을 사용하고 있습니다. 아래 예제 ( mvn package빌드 항아리) :

<plugin>
    <groupId>org.dstovall</groupId>
    <artifactId>onejar-maven-plugin</artifactId>
    <version>1.3.0</version>
    <executions>
        <execution>
            <configuration>
                <mainClass>com.company.MainClass</mainClass>
            </configuration>
            <goals>
                <goal>one-jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

해당 플러그인의 저장소를 추가해야합니다.

<pluginRepositories>
    <pluginRepository>
        <id>onejar-maven-plugin.googlecode.com</id>
        <url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url>
    </pluginRepository>
</pluginRepositories>


답변

maven-dependency-plugin을 사용할 수 있지만 문제는 실행 가능한 JAR을 작성하는 방법이었습니다. 그렇게하려면 Matthew Franglen의 응답을 다음과 같이 변경해야합니다 (btw, 종속성 플러그인을 사용하면 깨끗한 대상에서 시작할 때 빌드하는 데 시간이 더 걸립니다) :

<build>
    <plugins>
        <plugin>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>fully.qualified.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>unpack-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>unpack-dependencies</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
    <resources>
        <resource>
            <directory>${basedir}/target/dependency</directory>
        </resource>
    </resources>
</build>