Як розмістити всі необхідні файли JAR у папці бібліотеки всередині остаточного файлу JAR разом із Maven?


104

Я використовую Maven в моєму автономному додатку, і я хочу упакувати всі залежності в моєму файлі JAR всередині папки бібліотеки, як згадується в одній з відповідей тут:

Як я можу створити виконуваний JAR із залежностями за допомогою Maven?

Я хочу, щоб мій остаточний файл JAR мав папку бібліотеки, яка містить залежності у вигляді файлів JAR, а не як те, maven-shade-pluginщо встановлює залежності у вигляді папок, як ієрархія Maven у папці .m2.

Ну, насправді поточна конфігурація робить те, що я хочу, але у мене виникають проблеми з завантаженням файлів JAR під час запуску програми. Я не можу завантажити заняття.

Ось моя конфігурація:

<plugins>

    <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}/classes/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>com.myapp.MainClass</mainClass>
                </manifest>
            </archive>
        </configuration>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.6</source>
            <target>1.6</target>
        </configuration>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
            <execution>
                <id>install</id>
                <phase>install</phase>
                <goals>
                    <goal>sources</goal>
                </goals>
            </execution>
        </executions>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.5</version>
        <configuration>
            <encoding>UTF-8</encoding>
        </configuration>
    </plugin>

</plugins>

Проект відмінно працює від Eclipse, і файли JAR поміщаються в папку бібліотеки всередині мого остаточного файлу JAR, як я хочу, але при запуску остаточного файлу JAR з цільової папки я завжди отримую ClassNotFoundException:

Exception in thread "main" java.lang.NoClassDefFoundError: org/springframework/context/ApplicationContext
Caused by: java.lang.ClassNotFoundException: org.springframework.context.ApplicationContext
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
Could not find the main class: com.myapp.MainClass. Program will exit.

Як я можу виправити цей виняток?


1
яку команду ви використовуєте для запуску банку? напевно, ви можете віддати перевагу плагін Maven Exec?
Андрій Борисов

Чи є повідомлення про виключення застарілим порівняно з файлом POM? Здається, основний клас com.myapp.MainClassшукають, ні com.tastycafe.MainClass.
Дункан Джонс

@Duncan Jones, проблема копіювання вставки, я відредагував питання
Махмуд Салех

3
Зауважте, що якщо ви хочете баночки всередині банки, то стандартні завантажувачі класів на Java не можуть їх зрозуміти.
Thorbjørn Ravn Andersen

Як змусити її розмістити залежності Maven у папці lib, але поза JAR?
ed22

Відповіді:


81

Далі - моє рішення. Перевірте, чи працює він для вас:

<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}/classes/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>test.org.Cliente</mainClass> -->
            </manifest>
            <manifestEntries>
                <Class-Path>lib/</Class-Path>
            </manifestEntries>
        </archive>
    </configuration>
</plugin>

Перший плагін встановлює всі залежності в папку target / класів / lib, а другий включає папку бібліотеки у остаточному файлі JAR і конфігурує Manifest.mfфайл.

Але тоді вам потрібно буде додати спеціальний код завантаження для завантаження файлів JAR.

Або, щоб уникнути завантаження власних класів, ви можете використовувати "$ {project.build.directory} / lib, але в цьому випадку у вас немає залежностей всередині остаточного файлу JAR, що перемагає мету.

Минуло два роки, як поставили запитання. Проблема вкладених файлів JAR все ж зберігається. Я сподіваюся, що це комусь допоможе.


1
Використання: mvn install, cd target, java -jar MyJarFile-1.0.jar
djb

що я сумую? Це створює маніфестний запис класного шляху, що містить "lib /" та всю окрему банку з папки lib. Це призначено? Чому?
розрив

2
Це спрацювало після того, як я змінив "$ {project.build.directory} /
class

1
На жаль, включаються залежності, оголошені як передбачені.
Філіпп Джозеффі

@Rajendra дякую, що допомогло: $ {project.build.directory} / lib
Mindaugas K.

30

Оновлено:

<build> 
  <plugins> 
    <plugin> 
    <artifactId>maven-dependency-plugin</artifactId> 
    <executions> 
      <execution> 
        <phase>install</phase> 
          <goals> 
            <goal>copy-dependencies</goal> 
          </goals> 
          <configuration> 
             <outputDirectory>${project.build.directory}/lib</outputDirectory> 
          </configuration> 
        </execution> 
      </executions> 
    </plugin> 
  </plugins> 
</build> 

4
це ставить папку lib за межами банки (що не те, що я хочу). це краще, ніж ставити кришку всередину банки? і як доставити заявку клієнту в цьому випадку?
Махмуд Салех

зараз мені зрозуміліше. дозвольте мені здійснити пошук у Google. Але я хотів би знати, чому ви хочете скопіювати весь jar jar-файл у вказану папку всередині виконуваного файлу jar. Якщо всі файли jar залежно від файлу jar, то чому їх потрібно знаходити в папці lib?
Ахмет Каракая

23

Найпростіший і найефективніший спосіб - використовувати плагін uber таким чином:

          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <finalName>uber-${artifactId}-${version}</finalName>
            </configuration>
        </plugin>

У вас буде денормовано все в одному файлі JAR.


використовувати його на додаток до моєї поточної конфігурації? і що саме робить цей плагін?
Махмуд Салех

15
я не хочу, щоб мій файл jar виглядав так, я хочу мати всі залежності в папці lib всередині файлу jar, як це робить Netbean.
Махмуд Салех

12

Пакувальник ісполняемиха Maven плагін може бути використаний саме для цієї мети: створення автономного Java - додатків , що містять всю залежність , як JAR - файли в папці конкретною.

Просто додайте наступне до свого pom.xmlвнутрішнього <build><plugins>розділу (обов'язково замініть значення mainClassвідповідно):

<plugin>
    <groupId>de.ntcomputer</groupId>
    <artifactId>executable-packer-maven-plugin</artifactId>
    <version>1.0.1</version>
    <configuration>
        <mainClass>com.example.MyMainClass</mainClass>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>pack-executable-jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Вбудований файл JAR розміщений у target/<YourProjectAndVersion>-pkg.jarпісля запуску mvn package. Всі його залежності від часу компіляції та часу виконання будуть включені у lib/папку у файлі JAR.

Відмова: Я автор плагіна.


Я спробував це, і можу сказати, він працює ... Як ви вже говорили, цей плагін створює файл jar із його бібліотеками (банками) в каталог lib в банку ... Конфігурація дійсно проста .. Я думаю, що це те, що автор цього питання очікує ... я дам вам свій голос ... Єдиний недолік, який я знайшов у цьому (ось чому я не міг його використовувати), є затримка, коли я виконую свій jar, і додаток відображається (приблизно 20 секунд), ймовірно, через процес реєстрації ліфтів у користувальницькому завантажувачі ... Але це чудовий підхід та відмінний плагін ...
Адам М. Гамбоа Г.


3

Ось як я це роблю:

    <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.2</version>
            <configuration>
                <appendAssemblyId>false</appendAssemblyId>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
                <archive>
                    <manifest>
                        <mainClass>com.project.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>

І тоді я просто біжу:

mvn assembly:assembly

1
Зауважте, що ви завжди повинні робити компіляцію перед рукою, тому що assemblyпросто помістіть те, що є в "цілі / класи" в JAR. Це забезпечить включення до JAR будь-яких змін, які ви нещодавно внесли у вихідний код. Таким чином, ви повинні зробити що - щось на кшталт: mvn clean compile assembly:assembly.
naXa

2

Я знайшов цю відповідь на питання:

http://padcom13.blogspot.co.uk/2011/10/creating-standalone-applications-with.html

Ви не тільки отримуєте залежні файли lib у папці lib, але й отримуєте директор bin з unix та dos виконуваним dos.

Виконаний файл в кінцевому підсумку викликає java аргументом -cp, який також містить список усіх ваших залежних ліб.

Весь лот знаходиться в папці для збирання всередині цільової папки. Епос.

============= Так, я знаю, що це стара тема, але вона все ще набирає високого значення в результатах пошуку, тому я подумала, що може допомогти комусь, як я.


1

Це явно проблема класового шляху. Враховуйте, що класовий шлях повинен трохи змінитися під час запуску програми поза IDE. Це відбувається тому, що IDE завантажує інші JAR щодо кореневої папки вашого проекту, тоді як у випадку остаточного JAR це зазвичай не відповідає дійсності.

Що мені подобається робити в цих ситуаціях - це скласти JAR вручну. Це займає у мене не більше 5 хвилин, і це завжди вирішує проблему. Я не пропоную вам це робити. Знайдіть спосіб використання Maven, це його мета.


@SoboLAN Побудова JAR вручну тут не є рішенням. Наміром є використання Maven, що є прямо протилежною "ручному"!
Дункан Джонс

@DuncanJones Ви абсолютно праві. Я припускаю, що він використовує Мейвена для цього. Однак я не маю досвіду з цим і не знав, яке саме рішення рекомендувати. Я відредагував свою відповідь, щоб це відобразити.
Radu Murzea
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.