Включая зависимости в банке с Maven
Есть ли способ заставить maven(2.0.9) включить все зависимости в один файл jar?
У меня есть проект сборки в один файл JAR. Я хочу, чтобы классы из зависимостей также копировались в банку.
Обновление: я знаю, что не могу просто включить файл JAR в файл JAR. Я ищу способ распаковать jar-файлы, указанные как зависимости, и упаковать файлы классов в мой jar-файл.
16 ответов
Вы можете сделать это, используя плагин 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>
В Maven 2 правильный способ сделать это - использовать плагин сборки Maven 2, у которого есть предопределенный файл дескриптора для этой цели, который вы можете просто использовать в командной строке:
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, им также нужно установить основной класс. Так что полная настройка должна быть.
<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>
<!-- 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>
Есть плагин Shade Maven. Он может использоваться для упаковки и переименования зависимостей (чтобы исключить проблемы с зависимостями в пути к классам).
Вы можете использовать только что созданную банку, используя <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>
Если вам (как и мне) особенно не нравится описанный выше подход jar-with-dependencies, я предпочитаю maven-решение - просто создать WAR-проект, даже если вы создаете только отдельное java-приложение:
Сделайте обычный maven jar-проект, который соберет ваш jar-файл (без зависимостей).
Кроме того, настройте военный проект maven (только с пустым файлом src/main/webapp/WEB-INF/web.xml, который позволит избежать предупреждения / ошибки в сборке maven), в котором ваш jar-проект имеет только зависимость, и сделайте свой jar-проект
<module>
под ваш военный проект. (Этот war-проект - всего лишь простая уловка, чтобы обернуть все ваши зависимости jar-файла в zip-файл.)Создайте военный проект для создания военного файла.
На этапе развертывания просто переименуйте ваш.war-файл в *.zip и разархивируйте его.
Теперь у вас должен быть каталог lib (который вы можете переместить куда хотите) с вашим jar-файлом и всеми зависимостями, необходимыми для запуска вашего приложения:
java -cp 'path/lib/*' MainClass
(Подстановочный знак в classpath работает в Java-6 или выше)
Я думаю, что это проще в установке в maven (не нужно возиться с плагином сборки), а также дает более четкое представление о структуре приложения (вы увидите номера версий всех зависимых jar-файлов в простом виде, и избегать засорения всего в один jar-файл).
http://fiji.sc/Uber-JAR дает отличное объяснение альтернатив:
Существует три распространенных метода построения Uber-JAR:
- Незатушеванная. Распакуйте все файлы JAR, затем упакуйте их в один JAR.
- Pro: Работает с загрузчиком классов Java по умолчанию.
- Con: файлы, присутствующие в нескольких файлах JAR с одним и тем же путем (например, META-INF/services/javax.script.ScriptEngineFactory), будут перезаписывать друг друга, что приведет к ошибочному поведению.
- Инструменты: плагин Maven Assembly, Classworlds Uberjar
- Затенение. То же, что и у затененных, но переименовывает (т. Е. "Затеняет") все пакеты всех зависимостей.
- Pro: Работает с загрузчиком классов Java по умолчанию. Предотвращает некоторые (не все) конфликты версий зависимостей.
- Con: файлы, присутствующие в нескольких файлах JAR с одним и тем же путем (например, META-INF/services/javax.script.ScriptEngineFactory), будут перезаписывать друг друга, что приведет к ошибочному поведению.
- Инструменты: плагин Maven Shade
- Баночка банок. Окончательный файл JAR содержит другие файлы JAR, встроенные в.
- Pro: предотвращает конфликты версий зависимостей. Все файлы ресурсов сохраняются.
- Con: Нужно связать специальный загрузчик классов "начальной загрузки", чтобы позволить Java загружать классы из упакованных файлов JAR. Отладка проблем загрузчика классов становится более сложной.
- Инструменты: Eclipse JAR File Exporter, One-JAR.
Мое окончательное решение для 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 чистая зависимость: пакет копий-зависимостей
создается фляга с зависимостями в папке 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>
Я нашел, что это самый ясный ответ; в других ответах здесь отсутствовали вещи, которые не были очевидны для меня, например, команда mvn clean package, а также добавление плагина отдельно в качестве зависимости. Все это, вероятно, очевидно для более привычных пользователей maven.
https://howtodoinjava.com/maven/executable-jar-with-dependencies/
Спасибо. Я добавил ниже фрагмент кода в файле POM.xml, и проблема с Mp решена, и я создал файл с толстыми банками, который включает все зависимые банки.
<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>
Отложив Maven в сторону, вы можете поместить библиотеки JAR в основной Jar, но вам нужно будет использовать свой собственный загрузчик классов.
Проверить этот проект: текст ссылки на один JAR
Я пытался сделать что-то подобное, но я не хотел, чтобы все банки были включены. Я хотел включить некоторые конкретные каталоги из данной зависимости. Кроме того, тег классификатора уже был занят, поэтому я не мог сделать:
<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>
- Я использовал maven-dependency-plugin и распаковал цель
- И распаковал то, что хотел
${project.build.directory}/classes
, иначе он будет опущен - Поскольку он был в каталоге классов, maven наконец поместил его в банку.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack</id>
<phase>prepare-package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>my.group</groupId>
<artifactId>my.artifact</artifactId>
<classifier>occupied</classifier>
<version>1.0</version>
<type>jar</type>
</artifactItem>
</artifactItems>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
<includes>aaa/**, bbb/**, ccc/**</includes>
</configuration>
</execution>
</executions>
</plugin>
Я создаю установщик, который работает как файл 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>
Этот пост может быть немного старым, но у меня тоже недавно была такая же проблема. Первое решение, предложенное Джоном Штауффером, является хорошим, но у меня были некоторые проблемы, так как я работаю этой весной. Я использую пружинные зависимости-файлы, которые я использую, имеет несколько файлов свойств и объявление xml-схем, которые имеют одинаковые пути и имена. Несмотря на то, что эти jar- файлы имеют одинаковые версии, maven-goal jar-with-dependencies перезаписывал файл тезисов последним найденным файлом.
В конце концов, приложение не удалось запустить, поскольку пружинные банки не смогли найти правильные файлы свойств. В этом случае решение, предложенное Rop, решило мою проблему.
Также с тех пор проект весенней загрузки теперь существует. У него есть очень крутой способ справиться с этой проблемой, предоставив maven цель, которая перегружает цель пакета и предоставляет собственный загрузчик классов. См. Spring-boots Справочное руководство
Чтобы упростить задачу, вы можете использовать плагин ниже.
<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>
com.nirav.certificate.CertificateUtility
</mainClass>
</configuration>
</execution>
</executions>
</plugin>