Как я могу создать исполняемый JAR с зависимостями, используя Maven? - PullRequest
2171 голосов
/ 22 февраля 2009

Я хочу упаковать свой проект в один исполняемый файл JAR для распространения.

Как сделать так, чтобы проект Maven упаковывал все JAR-файлы зависимостей в мой выходной JAR-файл?

Ответы [ 34 ]

2120 голосов
/ 22 февраля 2009
<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

Цель компиляции должна быть добавлена ​​перед сборкой: одиночный или другой код в вашем собственном проекте не включен.

Подробнее см. В комментариях.


Обычно эта цель связана с фазой сборки для автоматического выполнения. Это обеспечивает сборку JAR при выполнении mvn install или при развертывании / выпуске.

<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>
321 голосов
/ 01 декабря 2010

Вы можете использовать плагин зависимостей для генерации всех зависимостей в отдельном каталоге до фазы пакета, а затем включить их в путь к классу манифеста:

<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 в качестве OutputDirectory для интеграции всех jar-файлов в основной jar, но затем вам нужно будет добавить собственный код загрузки классов для загрузки jar.

181 голосов
/ 02 июня 2014

Я писал о некоторых разных способах сделать это.

См. Исполняемый Jar с Apache Maven (WordPress)

или пример исполняемого jar-with-maven (GitHub)

Примечания

Эти плюсы и минусы предоставлены Stephan .


Для ручного развертывания

  • Плюсы
  • Cons
    • Зависимости выходят за финальную банку.

Копировать зависимости в определенный каталог

<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-файл исполняемым и Classpath Aware

<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 фактически выполняется с внешними элементами classpath.

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

Создание развертываемых архивов

Файл jar является исполняемым только с каталогом sibling ...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), каждый из которых содержит jar и lib/*.


Подключаемый модуль Apache Maven

  • Плюсы
  • Cons
    • Нет поддержки перемещения классов (используйте 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-плагин

  • Плюсы
  • Cons
    • Активно не поддерживается с 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>

Плагин Spring Boot Maven

  • За
  • Cons
    • Добавить потенциально ненужные классы, связанные с Spring и Spring Boot.
<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.

131 голосов
/ 26 февраля 2009

Принимая ответ без ответа и переформатируя его, мы имеем:

<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>
96 голосов
/ 22 сентября 2010

Используйте maven-shade-plugin, чтобы упаковать все зависимости в один uber-jar. Его также можно использовать для создания исполняемого файла jar, указав основной класс. Попытавшись использовать maven-assembly и maven-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>
19 голосов
/ 14 марта 2012

Долго использовал плагин maven , но я не смог найти решение проблемы с "already added, skipping". Сейчас я использую другой плагин - onejar-maven-plugin . Пример ниже (mvn package build jar):

<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>
17 голосов
/ 13 октября 2009

Вы можете использовать maven-dependency-plugin, но вопрос был в том, как создать исполняемый JAR. Для этого требуется следующее изменение ответа Мэтью Френглена (кстати, использование плагина зависимости занимает больше времени при запуске из чистой цели):

<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>
15 голосов
/ 11 марта 2009

Другой вариант, если вы действительно хотите переупаковать содержимое JAR-файлов внутри вашего единственного результирующего JAR-файла, - это плагин Maven Assembly . Распаковывает, а затем перепаковывает все в каталог через <unpack>true</unpack>. Тогда у вас будет второй проход, который встроит его в один массивный JAR.

Другой вариант - плагин OneJar . Это выполняет вышеуказанные действия по переупаковке за один шаг.

13 голосов
/ 13 августа 2011

Вы можете добавить следующее к вашему pom.xml :

<build>
<defaultGoal>install</defaultGoal>
<plugins>
  <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
      <source>1.6</source>
      <target>1.6</target>
    </configuration>
  </plugin>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>2.3.1</version>
    <configuration>
      <archive>
        <manifest>
          <addClasspath>true</addClasspath>
          <mainClass>com.mycompany.package.MainClass</mainClass>
        </manifest>
      </archive>
    </configuration>
  </plugin>
  <plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
      <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
      <archive>
        <manifest>
          <mainClass>com.mycompany.package.MainClass</mainClass>
        </manifest>
      </archive>
    </configuration>
    <executions>
      <execution>
        <id>make-my-jar-with-dependencies</id>
        <phase>package</phase>
        <goals>
          <goal>single</goal>
        </goals>
      </execution>
    </executions>
  </plugin>
</plugins>
</build>

После этого вам нужно переключиться через консоль в каталог, где находится файл pom.xml. Затем вы должны выполнить сборку mvn: single , и тогда ваш исполняемый JAR-файл с зависимостями будет скомпилирован. Вы можете проверить это, переключившись в выходной (целевой) каталог с помощью cd ./target и запустив jar с помощью команды, аналогичной java -jar mavenproject1-1.0-SNAPSHOT-jar-with-dependencies .jar .

Я проверял это с Apache Maven 3.0.3 .

11 голосов
/ 26 октября 2017

Вы можете использовать плагин Maven-Shade для создания Uber Jar, как показано ниже

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
...