Этот пост будет нацелен на интересную, но довольно мощную концепцию: упаковывать ваше приложение в один исполняемый файл JAR, также известный как один или толстый JAR.
Мы привыкаем к большим архивам WAR, которые содержат все зависимости, упакованные вместе в какую-то общую структуру папок. С JAR-подобной упаковкой история немного другая: для того, чтобы сделать ваше приложение работоспособным (через java -jar ), все зависимости должны быть предоставлены через параметр classpath или переменную среды. Обычно это означает, что там будет какая-нибудь папка lib со всеми зависимостями и какой-нибудь исполняемый скрипт, который будет выполнять работу по созданию classpath и запуску JVM. Плагин Maven Assembly хорошо известен для распространения приложений такого рода.
Несколько иной подход заключается в том, чтобы упаковать все зависимости вашего приложения в один и тот же файл JAR и сделать его работоспособным без каких-либо дополнительных параметров или сценариев. Звучит здорово, но … это не сработает, если вы не добавите немного волшебства: познакомьтесь с проектом One-JAR .
Давайте кратко опишем проблему: мы пишем отдельное приложение Spring, которое можно запустить, просто набрав java -jar <our-app.jar> .
Как всегда, давайте начнем с нашего файла POM, который будет довольно простым
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | <projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelversion>4.0.0</modelversion>    <groupid>com.example</groupid>    <artifactid>spring-one-jar</artifactid>    <version>0.0.1-SNAPSHOT</version>    <packaging>jar</packaging>    <name>spring-one-jar</name>    <properties>        <project.build.sourceencoding>UTF-8</project.build.sourceencoding>        <org.springframework.version>3.1.1.RELEASE</org.springframework.version>    </properties>    <dependencies>        <dependency>            <groupid>cglib</groupid>            <artifactid>cglib-nodep</artifactid>            <version>2.2</version>        </dependency>        <dependency>            <groupid>org.springframework</groupid>            <artifactid>spring-core</artifactid>            <version>${org.springframework.version}</version>        </dependency>        <dependency>            <groupid>org.springframework</groupid>            <artifactid>spring-context</artifactid>            <version>${org.springframework.version}</version>        </dependency>    </dependencies></project> | 
Наше примерное приложение загрузит контекст Spring , получит некоторый экземпляр компонента и вызовет для него метод. Наш компонент называется SimpleBean и выглядит так:
| 1 2 3 4 5 6 | packagecom.example;publicclassSimpleBean {    publicvoidprint() {        System.out.println( 'Called from single JAR!');    }} | 
Влюбившись в конфигурацию Spring Java, давайте определим наш контекст как аннотированный AppConfig POJO:
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 | packagecom.example.config;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importcom.example.SimpleBean;@ConfigurationpublicclassAppConfig {    @Bean    publicSimpleBean simpleBean() {        returnnewSimpleBean();    }} | 
И, наконец, наше приложение Starter с main () :
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 | packagecom.example;importorg.springframework.context.ApplicationContext;importorg.springframework.context.annotation.AnnotationConfigApplicationContext;importcom.example.config.AppConfig;publicclassStarter {    publicstaticvoidmain( finalString[] args ) {        ApplicationContext context = newAnnotationConfigApplicationContext( AppConfig.class);        SimpleBean bean = context.getBean( SimpleBean.class);        bean.print();    }} | 
Добавление нашего основного класса в META-INF / MANIFEST.MF позволяет использовать возможности Java для запуска файла JAR без явного указания класса с помощью метода main () . Плагин Maven JAR может помочь нам в этом.
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | <build>    <plugins>        <plugin>            <groupid>org.apache.maven.plugins</groupid>            <artifactid>maven-jar-plugin</artifactid>            <configuration>                <archive>                    <manifest>                        <mainclass>com.example.Starter</mainclass>                    </manifest>                </archive>            </configuration>        </plugin>    </plugins></build> | 
При попытке запустить java -jar spring-one-jar-0.0.1-SNAPSHOT.jar в консоль будет выведено исключение: java.lang.NoClassDefFoundError . Причина довольно проста: даже такое простое приложение, как это, уже требует, чтобы следующие библиотеки находились в пути к классам.
| 1 2 3 4 5 6 7 8 9 | aopalliance-1.0.jarcglib-nodep-2.2.jarcommons-logging-1.1.1.jarspring-aop-3.1.1.RELEASE.jarspring-asm-3.1.1.RELEASE.jarspring-beans-3.1.1.RELEASE.jarspring-context-3.1.1.RELEASE.jarspring-core-3.1.1.RELEASE.jarspring-expression-3.1.1.RELEASE.jar | 
Давайте посмотрим, что One-JAR может сделать для нас здесь. Благодаря наличию onejar-maven-plugin мы можем добавить его в раздел плагинов нашего POM-файла.
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 | <plugin>    <groupid>org.dstovall</groupid>    <artifactid>onejar-maven-plugin</artifactid>    <version>1.4.4</version>    <executions>        <execution>            <configuration>                <onejarversion>0.97</onejarversion>                <classifier>onejar</classifier>            </configuration>            <goals>                <goal>one-jar</goal>            </goals>        </execution>   </executions></plugin> | 
Кроме того, раздел pluginRepositories должен содержать этот репозиторий для загрузки плагина.
| 1 2 3 4 5 6 | <pluginrepositories>    <pluginrepository>        <id>onejar-maven-plugin.googlecode.com</id>    </pluginrepository></pluginrepositories> | 
В результате в целевой папке будет доступен другой артефакт с постфиксом one-jar : spring-one-jar-0.0.1-SNAPSHOT.one-jar.jar . Запуск этого с java -jar spring-one-jar-0.0.1-SNAPSHOT.one-jar.jar выведет на консоль:
| 1 | Called from single JAR! | 
Полностью запускаемое Java-приложение в виде одного распространяемого JAR- файла! Последний комментарий: хотя наше приложение выглядит довольно просто, One-JAR отлично работает для сложных, больших приложений, а также без каких-либо проблем. Пожалуйста, добавьте его в свой набор инструментов, это действительно полезный инструмент.
Спасибо One-JAR, ребята!
Ссылка: простая, но мощная концепция: упаковка вашего Java-приложения в один (или толстый) JAR от нашего партнера по JCG Андрея Редько в блоге Андрея Редько {devmind} .