Как создать автономное приложение с неповрежденными зависимостями с помощью Maven?

У меня есть настольное Java-приложение, созданное с использованием Maven 2 (но я могу перейти на Maven 3, если это поможет) с рядом зависимостей с открытым исходным кодом. Теперь я пытаюсь упаковать его как автономный, чтобы сделать его доступным для конечных пользователей без необходимости установки maven или чего-либо еще.

Я успешно использовал maven-assembly-plugin для создания одной банки, содержащей все зависимости, но на самом деле это не то, чего я хочу, потому что при использовании библиотек LGPL вы должны распространять библиотеки, которые вы используете, как отдельные банки.

Я хочу, чтобы Maven создал zip-архив, содержащий банку с моим кодом и MANIFEST.MF, который ссылается на другие банки, которые мне нужны, вместе с другими банками. Это кажется стандартной практикой, но я не понимаю, как это сделать.

Вот выдержка из моей пом.

     <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <encoding>UTF-8</encoding>
                    <compilerVersion>1.6</compilerVersion>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <argLine>-Dfile.encoding=UTF-8</argLine>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.company.widget.Main</mainClass>
                            <packageName>com.company.widget</packageName>
                            <addClasspath>true</addClasspath>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <archive>
                        <manifest>
                            <mainClass>com.company.widget.Main</mainClass>
                            <packageName>com.company.widget</packageName>
                            <addClasspath>true</addClasspath>
                        </manifest>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build> 

РЕДАКТИРОВАТЬ: Взято за идею Калса

создал файл с именем descriptor.xml

<?xml version="1.0" encoding="UTF-8"?>
<assembly
    xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
    <id>distribution</id>
    <formats>
        <format>zip</format>
    </formats>
    <dependencySets>
        <dependencySet>
            <scope>runtime</scope>
            <outputDirectory>lib</outputDirectory>
            <unpack>false</unpack>
        </dependencySet>
    </dependencySets>
</assembly>

и пом содержит:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>2.3</version>
    <configuration>
        <descriptors>
            <descriptor>assembly.xml</descriptor>
        </descriptors>
        <archive>
            <manifest>
                <mainClass>com.company.widget.cmdline.Main</mainClass>
                <packageName>com.company.widget</packageName>
                <addClasspath>true</addClasspath>
            </manifest>
        </archive>
    </configuration>
    <executions>
        <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Теперь поддерживает банку и помещает их все в папку lib, включая мой собственный код.


person Paul Taylor    schedule 19.04.2012    source источник
comment
Вы можете распространять свое приложение как простое приложение WebStart, для которого вам не нужен сервер приложений JEE, а только JNLP.   -  person Joop Eggen    schedule 19.04.2012
comment
хмарбасисе интересно, я думаю, что это этап после, хотя   -  person Paul Taylor    schedule 19.04.2012


Ответы (4)


Попробуйте создать собственный дескриптор сборки и добавить набор зависимостей и убедитесь, что вы указали unpack как false.

Используйте это как дескриптор сборки,

<?xml version="1.0" encoding="UTF-8"?>
<assembly
    xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
    <id>distribution</id>
    <formats>
        <format>zip</format>
    </formats>
    <dependencySets>
        <dependencySet>
            <scope>runtime</scope>
            <outputDirectory>lib</outputDirectory>
                        <useProjectArtifact>false</useProjectArtifact>
            <unpack>false</unpack>
        </dependencySet>
    </dependencySets>
</assembly>

Сохраните этот файл, чтобы сказать src/main/assembly/assembly.xml и обновите конфигурацию плагина сборки в pom.xml следующим образом.

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.2.1</version>
            <executions>
                <execution>
                    <id>assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>attached</goal>
                    </goals>
                    <configuration>
                           <descriptor>${basedir}/src/main/assembly/assembly.xml</descriptor>
                    </configuration>
                </execution>
            </executions>
        </plugin>

Вот ссылка на дескриптор сборки, если вам нужно что-то еще

http://maven.apache.org/plugins/maven-assembly-plugin/assembly.html

person Kalpak Gadre    schedule 19.04.2012
comment
Выглядит хорошо, но извините, куда это идет, это отдельный файл или он идет в pom, и я храню в своем pom материал, показанный в исходном вопросе. - person Paul Taylor; 19.04.2012
comment
Он будет помещен в отдельный файл, такой как Assembly.xml, который является вашим дескриптором сборки. Настройте плагин сборки, чтобы ссылаться на него. - person Kalpak Gadre; 19.04.2012
comment
Привет, это, по сути, работает, за исключением того, что мой собственный код также помещается в библиотеку, тогда как я только хочу, чтобы другие банки находились в папке lib, любые идеи, которые были бы замечательными, но я отметил ваш ответ как правильный. - person Paul Taylor; 19.04.2012
comment
Вам нужно включить ‹useProjectArtifact›false‹/useProjectArtifact› в дескриптор сборки. Смотрите обновленный ответ. - person Kalpak Gadre; 19.04.2012
comment
Хорошо, это удаляет мой код из библиотеки, но я не хотел, чтобы мой код вообще не отображался, я просто хотел, чтобы он отображался в указанном выше каталоге. Мне удалось это, добавив еще один набор зависимостей, но, к сожалению, созданный путь к классам манифеста не работает, потому что он не учитывает папку lib. Сказав все это, я думаю, что просто оставлю свой код в lib, так что проблема решена. - person Paul Taylor; 20.04.2012
comment
Немного не по теме. Если вы добавляете записи пути к классам в манифест, чтобы поместить их в путь к классам во время выполнения, вы также можете посмотреть classworlds. classworlds.codehaus.org/launchusage.html Я регулярно использую его, чтобы упростить сценарий запуска для заявление. Учитывая, что вы работаете над настольным приложением, я думаю, вы будете напрямую использовать runable jar? - person Kalpak Gadre; 20.04.2012
comment
По сути, (хотя в Windows я заворачиваю в exe, используя sourceforge.net/projects/winrun4j), Мне нужен только classpth моей банки, доступной в сценарии/командной строке, тогда пути к классам поддерживающих библиотек упоминаются в манифесте пути к классам в моей исполняемой банке. - person Paul Taylor; 20.04.2012

Вам следует проверить плагин Maven Appassembler. Вы можете получить гораздо более надежный пакет, используя его, чем собирая собственную сборку.

Он генерирует полезные сценарии запуска для Unix и Windows, которые позволяют вам устанавливать предопределенные параметры виртуальной машины JAVA, параметры командной строки и путь к классам.

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

Зависимости можно сохранить в «репозитории» в стиле Maven или использовать каталог «lib» в плоском стиле.

Вам все еще нужен плагин сборки для создания архива zip или tar.

Вот пример конфигурации appassembler:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>appassembler-maven-plugin</artifactId>
    <version>1.2.2</version>
    <configuration>
        <programs>
            <program>
                <mainClass>com.mytools.ReportTool</mainClass>
                <name>ReportTool</name>
            </program>
        </programs>
        <assembleDirectory>${project.build.directory}/ReportTool</assembleDirectory>
        <repositoryName>lib</repositoryName>
        <repositoryLayout>flat</repositoryLayout>
    </configuration>
    <executions>
        <execution>
            <id>assembly</id>
            <phase>package</phase>
            <goals>
                <goal>assemble</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Чтобы получить zip-архив, я использую эту сборку:

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
    <id>bin</id>
    <formats>
        <format>zip</format>
    </formats>
    <fileSets>
        <fileSet>
            <directory>${project.build.directory}/ReportTool</directory>
            <outputDirectory>/</outputDirectory>
            <includes>
                <include>/**</include>
            </includes>
        </fileSet>
    </fileSets>
</assembly>
person palto    schedule 26.07.2012

Насколько я знаю, библиотеки LGPL также можно распространять в своих собственных пакетах, если они нетронуты. Плагин сборки maven создает банку, содержащую исходные банки внутри папки lib архива. Пока вы выполняете LGPL.

Возможно, этот вопрос дает дополнительную информацию по этой теме.

(Отказ от ответственности: я не юрист, поэтому, пожалуйста, перепроверьте эту информацию;))

person magomi    schedule 19.04.2012
comment
Спасибо, я использовал jar-with-dependencies, который этого не делает, но предложенный Assembly.xml делает это - person Paul Taylor; 19.04.2012

Добавьте следующие плагины в pom.xml. Проверьте значение в тегах mainClass, classpathPrefix, addClasspath.

<plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>org.apache.camel.spring.Main</mainClass>
                        <classpathPrefix>lib/</classpathPrefix>
                        <addClasspath>true</addClasspath>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <descriptors>
                    <descriptor>src/assembly/some-assembly.xml</descriptor>
                </descriptors>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

Создайте файл some-assembly.xml в папке src/assembly, как показано ниже.

<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>distribution</id>
<formats>
    <format>zip</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<fileSets>
    <fileSet>
        <directory>${project.build.directory}</directory>
        <outputDirectory>/</outputDirectory>
        <includes>
            <include>*.jar</include>
        </includes>
    </fileSet>
</fileSets>
<dependencySets>
    <dependencySet>
        <scope>runtime</scope>
        <outputDirectory>/lib</outputDirectory>
        <useProjectArtifact>false</useProjectArtifact>
        <unpack>false</unpack>
    </dependencySet>
</dependencySets>

Note that useProjectArtifact flag to false, unpack flag to false. If root folder inside zip file is not required,then one can make includeBaseDirectory to false.

Это создаст файл name-version-distribution.zip. Внутри zip-файла будет имя-версия папки. Внутри этой папки будут присутствовать исполняемый файл jar и папка lib, содержащая все файлы jar зависимостей. Проверьте файл manifest.MF исполняемого файла jar. Он содержит информацию как об основном классе, так и о пути к классам.

person PShetty    schedule 12.03.2013