Включая зависимости в банке с Maven

353

Есть ли способ заставить maven (2.0.9) включить все зависимости в один файл jar?

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

Обновление: я знаю, что я не могу просто включить файл JAR в файл JAR. Я ищу способ распаковать файлы jar, указанные как зависимости, и упаковать файлы классов в мой файл jar.

гонщик
источник
2
Как включить файл JAR в файл JAR в Maven?
Куш Патель

Ответы:

488

Вы можете сделать это с помощью плагина maven-assembly с дескриптором jar-with-dependencies. Вот соответствующий фрагмент из одного из наших pom.xml, который делает это:

  <build>
    <plugins>
      <!-- any other plugins -->
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
      </plugin>
    </plugins>
  </build>
Джон Штауффер
источник
30
attachedЦелью является устаревшим. Цель singleили directory-singleдолжна быть предпочтительнее.
Паскаль Thivent
16
directory-singleтеперь также устарела.
Джеймс МакМэхон
14
использование сингла рекомендуется на официальном сайте
mateuszb
42
В случае, если какие-то новые mvn люди застряли как я, добавьте плагин в <plugins> внутри <build>, который находится внутри <project>.
DA
10
@ Christian.tucker В целевом каталоге есть второй jar, созданный следующим образом: ./target/example-0.0.1-SNAPSHOT.jar и ./target/example-0.0.1-SNAPSHOT-jar-with-dependencies.jar
технократ
145

В Maven 2 правильный способ сделать это - использовать плагин сборки Maven2, у которого есть предопределенный файл дескриптора для этой цели, который вы можете просто использовать в командной строке:

mvn assembly:assembly -DdescriptorId=jar-with-dependencies

Если вы хотите сделать этот jar исполняемым, просто добавьте основной класс для запуска в конфигурацию плагина:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <mainClass>my.package.to.my.MainClass</mainClass>
      </manifest>
    </archive>
  </configuration>
</plugin>

Если вы хотите создать эту сборку как часть обычного процесса сборки, вам следует привязать единственную или единственную цель каталога ( assemblyцель должна выполняться ТОЛЬКО из командной строки) к фазе жизненного цикла ( packageимеет смысл), что-то вроде этого:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <executions>
    <execution>
      <id>create-my-bundle</id>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
      <configuration>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        ...
      </configuration>
    </execution>
  </executions>
</plugin>

Адаптируйте configurationэлемент в соответствии со своими потребностями (например, с помощью материала манифеста, как говорится).

Паскаль Тивент
источник
Я пытаюсь именно это, однако плагин не запускается и файл JAR не создается, даже если сборка выполняется гладко. Есть ли распространенная ловушка, с которой я мог застрять?
Посеф
6
Это работает для меня, но есть квест. после сборки теперь создаются два jar-файла, один с проектом artifactid-version, а другой с artifactid-version- "jar-with-dependencies". Но я хочу построить только одну банку. Есть ли другой способ
Сувик Бхаттачарья,
38

Если вы хотите создать исполняемый файл JAR, им также нужно установить основной класс. Так что полная конфигурация должна быть.

    <plugins>
            <plugin>
                 <artifactId>maven-assembly-plugin</artifactId>
                 <executions>
                     <execution>
                          <phase>package</phase>
                          <goals>
                              <goal>single</goal>
                          </goals>
                      </execution>
                  </executions>
                  <configuration>
                       <!-- ... -->
                       <archive>
                           <manifest>
                                 <mainClass>fully.qualified.MainClass</mainClass>
                           </manifest>
                       </archive>
                       <descriptorRefs>
                           <descriptorRef>jar-with-dependencies</descriptorRef>
                      </descriptorRefs>
                 </configuration>
         </plugin>
   </plugins>
Abdiel
источник
2
Почему к имени jar добавляется «jar-with-dependencies» ?! Есть обходные пути?
Тина Дж
1
@Tina J вы можете добавить <appendAssemblyId>false</appendAssemblyId>внутрь <configuration>тега, чтобы исключить суффикс "-jar-with-dependencies" в окончательном имени.
ГКУ
19

Есть плагин Shade Maven . Он может использоваться для упаковки и переименования зависимостей (чтобы исключить проблемы с зависимостями в пути к классам).

Томас Юнг
источник
2
если вам не нравится jar-with-dependencies как часть имени файла.
Кайл
минимизировать функцию maven.apache.org/plugins/maven-shade-plugin/examples/…
Alex78191
это был лучший ответ для меня .. :)
Anand Varkey Philips
17

Вы можете использовать только что созданную банку, используя <classifier>тег.

<dependencies>
    <dependency>
        <groupId>your.group.id</groupId>
        <artifactId>your.artifact.id</artifactId>
        <version>1.0</version>
        <type>jar</type>
        <classifier>jar-with-dependencies</classifier>
    </dependency>
</dependencies>
Ласанта
источник
14

Если вам (как и мне) особенно не нравится описанный выше подход jar-with-dependencies , я предпочитаю maven-решение - просто создать WAR-проект, даже если вы создаете только отдельное java-приложение:

  1. Сделайте обычный maven jar-проект, который соберет ваш jar-файл (без зависимостей).

  2. Кроме того, настройте военный проект maven (только с пустым файлом src / main / webapp / WEB-INF / web.xml , который позволит избежать предупреждения / ошибки в сборке maven), в котором ваш jar-проект имеет только зависимость, и сделайте свой jar-проект <module>под свой war-проект. (Этот war-проект - всего лишь простая уловка, чтобы обернуть все ваши зависимости jar-файла в zip-файл.)

  3. Создайте военный проект для создания военного файла.

  4. На этапе развертывания просто переименуйте ваш .war-файл в * .zip и разархивируйте его.

Теперь у вас должен быть каталог lib (который вы можете переместить куда хотите) с вашим jar-файлом и всеми зависимостями, необходимыми для запуска вашего приложения:

java -cp 'path/lib/*' MainClass

(Подстановочный знак в classpath работает в Java-6 или выше)

Я думаю, что это проще в установке в maven (не нужно возиться с плагином сборки), а также дает более четкое представление о структуре приложения (вы увидите номера версий всех зависимых jar-файлов в простом виде, и избегать засорения всего в один jar-файл).

Rop
источник
Это то же самое, что Eclipse "Export as Runnable jar"? Поскольку при этом вы можете выбрать «упаковать все зависимости с помощью JAR», вы получите все зависимости в папке project-lib вместе с вашим jar-файлом.
WesternGun
@FaithReaper - Это может быть "то же самое", я никогда не пробовал это. Но я полагаю, что если вы используете Eclipse, он не легко поддается написанию сценариев, что является обязательным требованием, если вы хотите реализовать автоматизированную сборку + развертывание-конвейер. Например, пусть Jenkins-server выполняет сборку из вашего git source-repository или подобного.
Rop
12

http://fiji.sc/Uber-JAR дает отличное объяснение альтернатив:

Существует три распространенных метода построения Uber-JAR:

  1. Незатушеванная. Распакуйте все файлы JAR, затем упакуйте их в один JAR.
    • Pro: Работает с загрузчиком классов Java по умолчанию.
    • Con: файлы, присутствующие в нескольких файлах JAR с одним и тем же путем (например, META-INF / services / javax.script.ScriptEngineFactory), будут перезаписывать друг друга, что приведет к ошибочному поведению.
    • Инструменты: плагин Maven Assembly, Classworlds Uberjar
  2. Затенение. То же самое, что и unshaded, но переименовываете (т. Е. «Shade») все пакеты всех зависимостей.
    • Pro: Работает с загрузчиком классов Java по умолчанию. Предотвращает некоторые (не все) конфликты версий зависимостей.
    • Con: файлы, присутствующие в нескольких файлах JAR с одним и тем же путем (например, META-INF / services / javax.script.ScriptEngineFactory), будут перезаписывать друг друга, что приведет к ошибочному поведению.
    • Инструменты: плагин Maven Shade
  3. Баночка банок. Конечный файл JAR содержит другие файлы JAR, встроенные в него.
    • Pro: предотвращает конфликты версий зависимостей. Все файлы ресурсов сохраняются.
    • Con: Нужно связать специальный загрузчик классов "начальной загрузки", чтобы позволить Java загружать классы из упакованных файлов JAR. Отладка проблем загрузчика классов становится более сложной.
    • Инструменты: Eclipse JAR File Exporter, One-JAR.
Андре Валенти
источник
1
Не совсем верно в отношении сервисов, плагин Shade имеет преобразователи, и один из них предназначен для объединения содержимого файлов в META-INF/servicesкаталоге. Более подробная информация здесь: maven.apache.org/plugins/maven-shade-plugin/examples/…
vitro
7
        <!-- Method 1 -->
        <!-- Copy dependency libraries jar files to a separated LIB folder -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <configuration>
                <outputDirectory>${project.build.directory}/lib</outputDirectory>
                <excludeTransitive>false</excludeTransitive> 
                <stripVersion>false</stripVersion>
            </configuration>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <!-- Add LIB folder to classPath -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                    </manifest>
                </archive>
            </configuration>
        </plugin>


        <!-- Method 2 -->
        <!-- Package all libraries classes into one runnable jar -->
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <executions>
              <execution>
                <phase>package</phase>
                <goals>
                  <goal>single</goal>
                </goals>
              </execution>
            </executions>
            <configuration>
              <descriptorRefs>
                <descriptorRef>jar-with-dependencies</descriptorRef>
              </descriptorRefs>
            </configuration>
        </plugin>            
Лесли Ли
источник
4

Мое окончательное решение для Eclipse Luna и m2eclipse: Custom Classloader (скачать и добавить в свой проект, только 5 классов): http://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/plain/org. eclipse.jdt.ui / jar% 20in% 20jar% 20loader / org / eclipse / jdt / internal / jarinjarloader / ; этот загрузчик классов является самым лучшим из загрузчиков классов с одной флягой и очень быстрым;

<project.mainClass>org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader</project.mainClass> <project.realMainClass>my.Class</project.realMainClass>

Отредактируйте в JIJConstants "Rsrc-Class-Path" в "Class-Path"
mvn чистой зависимости: пакет copy-dependencies
создает jar с зависимостями в папке lib с тонким загрузчиком классов

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.java</include>
                <include>**/*.properties</include>
            </includes>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
            <includes>
                <include>**/*</include>
            </includes>
            <targetPath>META-INF/</targetPath>
        </resource>
        <resource>
            <directory>${project.build.directory}/dependency/</directory>
            <includes>
                <include>*.jar</include>
            </includes>
            <targetPath>lib/</targetPath>
        </resource>
    </resources>
<pluginManagement>
        <plugins>

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

                        <manifestEntries>
                            <Rsrc-Main-Class>${project.realMainClass}  </Rsrc-Main-Class>
                            <Class-Path>./</Class-Path>
                        </manifestEntries>

                    </archive>
                </configuration>
            </plugin>
<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </pluginManagement>
</build>
Glaucio Southier
источник
не работает плагин maven-dependency-plugin <outputDirectory>, всегда пишите в папку «зависимостей»
Glaucio Southier
создайте флягу с внутренней папкой "dependency", содержащей зависимости проекта, и поместите ее в MANIFEST.MF
Glaucio Southier
<resources> <resource> <directory> src / main / java </ directory> <include> <include> ** / *. java </ include> <include> ** / *. properties </ include> </ include > </ resource> <resource> <directory> src / main / resources </ directory> <filtering> true </ filtering> <include> <include> ** / * </ include> </ includes> <targetPath> META -INF / </ targetPath> </ resource> <resource> <directory> $ {project.build.directory} / dependency / </ directory> <include> <include> *. Jar </ include> </ include> < targetPath> lib / </ targetPath> </ resource> </ resources>
Глаусио Саутье
1
На основании этого ответа я создал этот проект. Вам не нужно ничего менять, кроме файла pom: github.com/raisercostin/jarinjarloader
raisercostin
0

Этот пост может быть немного старым, но у меня тоже недавно была такая же проблема. Первое решение, предложенное Джоном Штауффером, является хорошим, но у меня были некоторые проблемы, так как я работаю этой весной. Я использую пружинные зависимости-файлы, которые я использую, имеет несколько файлов свойств и объявление xml-схем, которые имеют одинаковые пути и имена. Несмотря на то, что эти jar- файлы получены из одних и тех же версий, maven-goal jar-with-dependencies перезаписывал файл тезисов последним найденным файлом.

В конце концов, приложение не удалось запустить, так как пружинные банки не смогли найти правильные файлы свойств. В этом случае решение, предложенное Rop, решило мою проблему.

Также с тех пор проект весенней загрузки теперь существует. У него есть очень крутой способ справиться с этой проблемой, предоставив maven цель, которая перегружает цель пакета и предоставляет собственный загрузчик классов. См. Spring-boots Справочное руководство

Франсуа Жерго
источник
0

Посмотрите на этот ответ:

Я создаю установщик, который работает как файл JAR Java, и ему нужно распаковать файлы WAR и JAR в соответствующие места в каталоге установки. Плагин зависимости можно использовать на этапе пакета с целью копирования, и он загрузит любой файл в хранилище Maven (включая файлы WAR) и запишет их там, где они вам нужны. Я изменил выходной каталог на $ {project.build.directory} / classes, и в результате я получил обычную задачу JAR, в которую включены мои файлы. Затем я могу извлечь их и записать в каталог установки.

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
    <execution>
        <id>getWar</id>
        <phase>package</phase>
        <goals>
            <goal>copy</goal>
        </goals>
        <configuration>
            <artifactItems>
                <artifactItem>
                    <groupId>the.group.I.use</groupId>
                    <artifactId>MyServerServer</artifactId>
                    <version>${env.JAVA_SERVER_REL_VER}</version>
                    <type>war</type>
                    <destFileName>myWar.war</destFileName>
                </artifactItem>
            </artifactItems>
            <outputDirectory>${project.build.directory}/classes</outputDirectory>
        </configuration>
    </execution>
</executions>

millebi
источник
0

Спасибо. Я добавил ниже фрагмент кода в файле POM.xml, и проблема с Mp решена, и создаю файл с полным jar-файлом, который включает все зависимые jar-файлы.

<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>single</goal>
                </goals>
            </execution>
        </executions>
        <configuration>
            <descriptorRefs>
                <descriptorRef>dependencies</descriptorRef>
            </descriptorRefs>
        </configuration>
    </plugin>
</plugins>
Раджив Ратор
источник