Включая зависимости в банке с 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>

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-файл).


Это то же самое, что 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>

не работает плагин 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>


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>
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.