Как создать jar файл

Обновлено: 04.07.2024

Это пост заметка о том, как я познакомился с языком Kotlin, какие использовал для этого ресурсы, инструменты, и как я собрал его в jar и запустил в консоли.

В общем-то я PHP программист, немного заком с Java. На днях решил посмотреть Kotlin. Это менее строго типизированный язык от JetBrains до того, что он, по сути, статически типизированный. В этом его основное принципиальное отличие от Java, плюс Kotlin имеет свой приятный синтаксис. Kotlin может быть скомпилирован в JVM или JavaScript.

Инструкции по установке там же на сайте. Версия 13+.

Плагин добавляет автозаполнение и возможность создавать Kotlin проекты.
Так же добавляются инструменты для компиляции Kotlin.

Особенность Kotlin в том, что он полностью совместим с Java. Т.е. код, написанный на Kotlin можно вызывать в Java и наоборот. Следовательно, все инструменты и библиотеки, которые используются для работы с Java, применимы и для Kotlin.

Если проект в IDE был создан не Kotlin изначально, то после установки плагина можно включить поддержку Kotlin. После включения в проект будут доаблены jar библиотеки Kotlin в директорию /lib.

Я включил Kotlin и написал следующий код для теста в папке /src/testing:

Для начала я выполнял в IDE файл котлина отдельно, чтобы убедиться, что плагин работает и код компилируется.

Потом я создал java класс:

Тут видно, что я хочу принять аргумент и передать его напрямую в котлин. В котлине же я использовал пример с языками и добавил еще один свой, который зависит от аргумента — моего ник нейма. В Java можно вызывать методы и получать доступ к переменным из котлина путем вызова — ИмяпакетаPackage.имяметода().

Если правильно настроить в IDE выполнение проекта, то можно задать с каким аргументом вызывать программу. Но это очень не удобно, я хотел бы менять аргумент на лету, чтобы отловить ошибки, для тестироавния. Мне нужно было собрать jar для запуска из консоли.
В проекте не было maven изначально, и я его туда добавил.

Тут используется настройка для kotlin-maven-plugin, где указывается, в какой директории искать файлы.
Так же, используется maven-jar-plugin. Тут очень важно правильно прописать < manifest >, иначе предстоит долго разбираться, почему jar не запускается с ошибкой "No Main Manifest Attribute".
После билда в директории /target будет лежать jar проекта. В Idea есть отдельное окно maven projects, откуда удобно управлять построением.

Чтобы запустить jar обычно выполняется команда

В моем случае это не сработало, т.к. я не воспользовался плагином maven, который бы добавил jar библиотеку котлина в билд.
Следовательно я получаю ошибку

Отсюда понятно, что не находится Kotlin библиотека.
Правильный вызов с указанием jar зависимости такой

Теперь код работает верно. Как видно, я получил аргумент в java, вывел его, далее я передал его в kotlin, и на его основе отработала конструкция when (по смыслу похожа на switch-case).

Для того, чтобы собрать jar с включением зависимых jar в билд, можно воспользоваться плагином maven — maven-dependency-plugin. Или onejar-maven-plugin к проекту one-jar.

Я решил использовать one-jar.

Далее пересобрать проект.


В директории /target появится файл имяпроекта.one-jar.jar. Его можно вызвать обычным методом.

На этом настройка проекта для меня закончена. Далее можно изучать Kotlin по приведенным выше ссылкам на документацию.
Лично мне язык очень понравился. Несомненно он займет свою нишу, так же, как и язык hack, который разрабатывает Facebook, как свою версию PHP.

“Java-проект от А до Я”: Реализуем развертывание приложения - 1

Всем привет. Продолжаем цикл статей по написанию своего проекта.

Сортируем ветки

  • JRTB-0
  • JRTB-2
  • JRTB-3
  • STEP_1_JRTB-0 — первый шаг
  • STEP_2_JRTB-2 — второй шаг
  • STEP_3_JRTB-3 — третий шаг

Немного о докере

Что такое Docker? Вкратце — это инструмент, с помощью которого можно быстро и безопасно развертывать (деплоить) приложения, создавая для них закрытую инфраструктуру, необходимую только для них. Пока что сложно, я понимаю. В общем и целом докер можно понимать как платформу для разработки, где можно быстро и эффективно работать. Докер можно понимать как программу, которая работает на сервере. Эта программа имеет возможность хранить контейнеры с приложениями. Что такое контейнер? Это отдельная инфраструктура, в которую можно добавить все, что нужно. Например для Java-приложения нам нужна JRE, чтобы запустить приложение, вот контейнер будет иметь это, нужно будет еще какое-то программное обеспечение — можно добавить это. А может быть, нам нужен Линукс и Tomcat сервлет контейнер. Такое тоже можно будет сделать. Контейнеры создаются на основе image (образа): то есть, это определенный шаблон в котором написано все необходимое для создания докер контейнера. Как создать этот образ? В нашем случае нам нужно будет создать файл Dockerfile в корне проекта с описанием того, что должно быть в контейнере. Так как мы не хотим где-то показывать токен бота, придется извернуться и передавать его каждый раз, когда мы захотим развертывать приложение. Более детально об этой теме почитать можно здесь и здесь.

Пишем JRTB-13

Нужно настроить быстрый и легкий процесс развертывания (деплоя) нашего приложения на сервер. То есть на машину, которая работает 24/7. За основу возьмем докер. Но задачи в нашем списке, которая бы отвечала за добавление этой функциональности, нет. Как-то я его пропустил при создании. Ничего страшного, сейчас создадим. Заходим на вкладку создания issue на гитхаб и выбираем Feature Request:Добавляем описание задачи, критерии его приемки, устанавливаем, к какому проекту этот issue относится и можно создавать новое issue:Теперь чтобы показать, что задача взята в работу, сменим статус задачи с To do на In Progress:Это будет сложная статья. Если будут проблемы — пишите в комментариях: я буду следить и отвечать на них в меру сил. Такой будет небольшой Customer Support :D

Создаем Dockerfile

Создаем docker-compose.yml

Хорошо бы вам про YAML формат почитать отдельно, а то статья и так уже растет, как на дрожжах. Для нас это просто еще одно описание переменных по типу .properties. Только в пропертях записывается через точку, а в YAML это делается немного красивее. Например, так. Две переменные в .properties: javarush.telegram.bot.name=ivan javarush.telegram.bot.token=pupkin А вот в .yaml (тоже самое что и .yml) будет это так: Второй вариант более красивый и понятный. Пробелы должны быть именно такие, как указаны выше. Как-нибудь переведем наши application.properties и application.yml. Для начала нужно его создать. В корне проекта создаем файл docker-compose.yml и записываем туда следующее: Первая строка — это версия docker-compose. services: говорит о том, что все следующие строки после этого (будут сдвинуты) — относятся к сервисам, которые мы настраиваем. У нас такой пока только один — java-приложение под названием jrtb . И уже под ним будут все его настройки. Например, build: context: . говорит о том, что мы будем искать Dockerfile в той же директории, что и docker-compose.yml. А вот секция environment: будет отвечать за то, чтобы мы передали в Dockerfile необходимые переменные среды (environment variables). Как раз то, что нам и нужно. Поэтому ниже мы переменные и передаем. Их docker-compose будет искать в переменных операционной среды сервера. Добавим их в баш скрипте.

Создаем баш скрипты

  • Dockerfile — файл для создания образа нашего приложения;
  • docker-compose.yml — файл с настройкой того, как мы будем запускать наши контейнеры;
  • start.sh — баш скрипт для развертывания нашего приложения;
  • stop.sh — баш скрипт для остановки нашего приложения.

И в README добавим новый параграф с описанием того, как деплоить наше приложение:

Разумеется, все пишет на английском. Уже как обычно, в нашей новосозданной ветке STEP_4_JRTB-13 создаем новый коммит с именем: JRTB-13: implement deployment process via docker и делаем пуш. Я перестаю подробно останавливаться на вещах, которые я уже описывал в прошлых статьях. Не вижу смысла повторять одно и тоже. К тому же, кто разобрался и сделал у себя, у того вопросов не возникнет. Это я о том, как создать новую ветку, как создать коммит, как запушить коммит в репозиторий.

“Java-проект от А до Я”: Реализуем развертывание приложения - 8

За сегодня я показал тьму новой информации, которую нужно хорошо обдумать и расширить дополнительным чтением. Самое главное: при помощи ОДНОЙ(. ) команды все необходимое для развертывания нашего приложения будет сделано. Это настолько классно, что я даже передать не могу вам. Да, пришлось потратить приличное количество времени в документации докера, чтобы понять, как правильно пробрасывать переменные. С этого момента телеграм-бот всегда будет работать на последней версии main ветки. Ссылка на телеграм-бота. Сегодня не будут ссылок на материалы, которые хорошо бы прочесть: ответственность лежит на вас. Нужно учиться искать информацию. Все, кто подписан на мой телеграм-канал, узнали о деплое бота почти сразу же. Друзья, нравится проект? Ставьте ему звезду! Так он станет более популярным и больше людей смогут узнать о нем и поучиться. Традиционно предлагаю зарегистрироваться на GitHub и подписаться на мой аккаунт, чтобы следить за этой серией и другими моими проектами, которые я веду там. Теперь мы готовы подключать базу данных. Следующая статья будет бооольшая и в ней мы сделаем все необходимое для работы с БД. Все описание — в JRTB-1.

Обычно удобно объединять множество файлов классов Java в один архивный файл.

В этом уроке мы рассмотрим все тонкости работы с jar – или J ava AR chive – файлами на Java.

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

2. Настройка программы Java

Прежде чем мы сможем создать запускаемый jar-файл, наше приложение должно иметь класс с основным методом . Этот класс обеспечивает нашу точку входа в приложение:

3. Команда Jar

Теперь, когда мы все настроили, давайте скомпилируем наш код и создадим наш jar-файл.

Мы можем сделать это с помощью javac из командной строки:

Команда javac создает JarExample.class в каталоге com/baeldung/jar . Теперь мы можем упаковать это в файл jar.

3.1. Использование параметров по умолчанию

Чтобы создать файл jar, мы будем использовать кувшин команда.

Чтобы использовать команду jar для создания файла jar, нам нужно использовать опцию c , чтобы указать, что мы создаем файл, и опцию f , чтобы указать файл:

3.2. Установка основного класса

Полезно, чтобы манифест файла jar включал основной класс.

Манифест-это специальный файл в банке, расположенный в каталоге META-INF и названный MANIFEST.MF . Файл манифеста содержит специальную метаинформацию о файлах в файле jar.

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

Используя опцию e , мы можем указать нашу точку входа, и команда jar добавит ее в сгенерированный файл манифеста.

Давайте запустим jar с указанной точкой входа:

3.3. Обновление содержания

Допустим, мы внесли изменения в один из наших классов и перекомпилировали его. Теперь нам нужно обновить наш jar-файл.

Давайте используем команду jar с параметром u для обновления ее содержимого:

3.4. Настройка файла манифеста

В некоторых случаях нам может потребоваться больше контроля над тем, что входит в наш файл манифеста. Команда jar предоставляет функциональные возможности для предоставления нашей собственной информации о манифесте.

Давайте добавим частичный файл манифеста с именем example_manifest.txt чтобы ваше приложение установило нашу точку входа:

Информация о манифесте, которую мы предоставляем, будет добавлена к тому, что генерирует команда jar, так что это единственная строка, которая нам нужна в файле.

Важно, чтобы мы заканчивали наш файл манифеста символом |/newline . Без новой строки наш файл манифеста будет молча проигнорирован.

С этой настройкой давайте снова создадим нашу банку, используя нашу информацию о манифесте и опцию m :

3.5. Подробный Вывод

Если нам нужна дополнительная информация из команды jar , мы можем просто добавить опцию v для verbose.

Давайте запустим нашу команду jar с параметром v :

4. Использование Maven

4.1. Конфигурация по Умолчанию

Мы также можем использовать Maven для создания нашей банки. Поскольку Maven предпочитает условность конфигурации, мы можем просто запустить пакет для создания нашего jar-файла.

По умолчанию наш jar-файл будет добавлен в папку target в нашем проекте.

4.2. Указание основного класса

Мы также можем настроить Maven для указания основного класса и создания исполняемого jar-файла .

5. Использование Пружинного Ботинка

5.1. Использование Maven и Defaults

Если мы используем Spring Boot с Maven, мы должны сначала подтвердить, что наш параметр упаковки установлен в jar , а не war в нашем pom.xml файл.

Как только мы узнаем, что это настроено, мы можем запустить пакет цель:

5.2. Установка точки входа

Установка нашего основного класса-это то, где мы находим различия между созданием jar с обычным Java-приложением и fat jar для приложения Spring Boot . В приложении Spring Boot основной класс на самом деле является org.springframework.boot.loader.Ярлаунчер .

Хотя наш пример не является приложением Spring Boot, мы могли бы легко настроить его как консольное приложение Spring Boot .

Наш основной класс должен быть указан как начальный класс:

Мы также можем использовать Gradle для создания Spring Boot fat jar .

6. Запуск банки

6.1. Вывод основного класса

Поскольку мы пошли дальше и убедились, что наш основной класс указан в манифесте, мы можем использовать опцию -jar команды java для запуска нашего приложения без указания основного класса:

6.2. Указание основного класса

Мы также можем указать основной класс, когда мы запускаем наше приложение. Мы можем использовать опцию -cp , чтобы убедиться, что наш jar-файл находится в пути к классу, а затем предоставить ваш основной класс в формате package.className :

Использование разделителей путей вместо формата пакета также работает:

6.3. Перечисление содержимого банки

Мы можем использовать команду jar для перечисления содержимого нашего файла jar:

6.4. Просмотр файла манифеста

Поскольку может быть важно знать, что находится в нашем файле MANIFEST.MF , давайте рассмотрим быстрый и простой способ заглянуть в содержимое, не выходя из командной строки.

Давайте воспользуемся командой unzip с параметром-p:

7. Заключение

В этом уроке мы настроим простое Java-приложение с классом main .

Затем мы рассмотрели три способа создания jar-файлов: с помощью команды jar , с помощью Maven и с помощью приложения Maven Spring Boot.

После того, как мы создали наши jar-файлы, мы вернулись в командную строку и запустили их с выведенным и заданным основным классом.

Мы также узнали, как отображать содержимое файла и как отображать содержимое одного файла в банке.


Когда ваше программное приложение выходит за пределы десятка строк кода, вам, вероятно, следует разделить код на несколько классов. На этом этапе встает вопрос о том, как их распределить. В Java классическим форматом является Java-архив, более известный как JAR. Но реальные программы, вероятно, зависят от других JAR.

Цель этой статьи - описать способы создания самодостаточных исполняемых (self-contained executable) JAR, также известных как uber-JAR или fat JAR.

Что такое самодостаточный JAR?

JAR — это просто набор файлов классов. Чтобы быть исполняемым, его файл META-INF/MANIFEST.MF должен указывать на класс, реализующий метод main() . Это делается с помощью атрибута Main-Class . Вот пример:

У MainClass метод static main(String…​ args)

Работа с classpath

Большинство программ зависит от существующего кода. Java предоставляет концепцию classpath. Classpath - это список элементов пути, который будет просматриваться в runtime, что поможет найти зависимый код. При запуске классов Java вы определяете classpath с помощью параметра командной строки -cp :

Java runtime создает classpath , объединяя все классы из всех связанных JAR и добавляя при этом главный класс.

Новые проблемы возникают при дистрибуции JAR, которые зависят от других JAR:

Вам необходимо синхронизировать версии библиотек.

Что еще более важно, аргумент -cp не работает с JAR. Чтобы ссылаться на другие JAR, classpath должен быть задан в манифесте JAR через атрибут Class-Path :

3. По этой причине вам необходимо поместить JAR в то же место, относительное или абсолютное, в целевую файловую систему в соответствии с манифестом. Это означает, что сначала нужно открыть JAR и прочитать манифест.

Одним из способов решения этих проблем является создание уникальной единицы развертывания, которая содержит классы из всех JAR и может быть распространена как один артефакт. Существует несколько вариантов создания таких JAR:

Плагин Spring Boot (Для проектов Spring Boot)

Плагин Apache Assembly

Assembly Plugin для Apache Maven позволяет разработчикам объединять результаты проекта в единый распространяемый архив, который также содержит зависимости, модули, документацию сайта и другие файлы.

— Плагин Apache Maven Assembly

Одним из принципов Maven является создание одного артефакта на проект. Хотя бывают исключения, например, Javadoc и исходный код, но в целом, если вам нужно несколько артефактов, нужно создавать один проект на каждый артефакт. Идея плагина Assembly заключается в том, чтобы обойти это правило.

Плагин Assembly полагается на специальный конфигурационный файл assembly.xml . Он позволяет вам выбирать, какие файлы будут включены в артефакт. Обратите внимание, что конечный артефакт не обязательно должен быть JAR: конфигурационный файл позволяет вам выбирать между доступными форматами, например, zip, war и т.д.

Плагин регулирует общие случаи использования, предоставляя предварительно определенные сборки (assemblies). Среди них - распространение самодостаточных JAR. Конфигурация выглядит следующим образом:

Ссылайтесь на предварительно определенную самодостаточную конфигурацию JAR

Установите главный класс для исполнения

Выполните single <goal>

Привяжите <goal> к package после формирование исходного JAR

Запуск mvn package дает два артефакта:

Первый JAR имеет то же содержимое, что и тот, который был бы создан без плагина. Второй — это самодостаточный JAR. Вы можете выполнить его следующим образом:

Причина в том, что разные JAR предоставляют разные ресурсы по одному и тому же пути, как например с META-INF/spring.factories .

Зачастую плагин следует стратегии "побеждает последний записавший". Порядок основывается на имени JAR.

С помощью Assembly вы можете нек. Если вам нужно объединить ресурсы, вы, вероятно, захотите использовать плагин Apache Shade.

Плагин Apache Shade

Плагин Assembly является общим; плагин Shade ориентирован исключительно на задачу создания самодостаточных JAR.

Этот плагин предоставляет возможность упаковать артефакт в uber-jar, включая его зависимости, и оттенить — т.е. переименовать — пакеты некоторых зависимостей.

— Плагин Apache Maven Shade

Плагин основан на концепции преобразователей: каждый преобразователь отвечает за работу с одним типом ресурсов. Преобразователь может копировать ресурс как есть, добавлять статическое содержимое, объединять его с другими и т.д.

Хотя вы можете разработать свой преобразователь, плагин предоставляет набор готовых преобразователей:


Конфигурация плагина Shade к приведенному выше Assembly выглядит следующим образом:

shade привязан к фазе package по умолчанию

Этот преобразователь предназначен для генерации файлов манифеста

Выполните ввод Main-Class

Настройте финальный JAR так, чтобы он был многорелизным JAR. Это необходимо в случае, когда любой из исходных JAR является многорелизным JAR

Запуск mvn package дает два артефакта:

<name>-<version>.jar : самодостаточный исполняемый JAR

original-<name>-<version>.jar : "обычный" JAR без встроенных зависимостей

При работе с проектом, взятым за образец, финальный исполняемый файл все еще не работает так, как ожидалось. Действительно, во время сборки появляется множество предупреждений о дублировании ресурсов. Два из них мешают корректной работе проекта. Чтобы правильно их объединить, нам нужно посмотреть на их формат:

META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat: этот Log4J2 файл содержит предварительно скомпилированные данные плагина Log4J2. Он закодирован в двоичном формате, и ни один из готовых преобразователей не может объединить такие файлы. Тем не менее, случайный поиск показывает, что кто-то уже занимался этой проблемой и выпустил преобразователь для работы с объединением.

META-INF/spring.factories : эти файлы, специфичные для Spring, они имеют формат "один ключ/много значений". Поскольку они текстовые, ни один готовый преобразователь не может корректно объединить их. Однако разработчики Spring предоставляют такую возможность (и многое другое) в своем плагине.

Чтобы настроить эти преобразователи, нам нужно добавить вышеуказанные библиотеки в качестве зависимостей к плагину Shade:

Объедините Log4J2 .dat файлы

Объедините файлы /META-INF/spring.factories

Добавьте необходимый код для преобразователей

Эта конфигурация работает! Тем не менее, есть оставшиеся предупреждения:

Лицензии, предупреждения и схожие файлы

Spring Boot файлы, например, spring.handlers , spring.schemas и spring.tooling

Файлы Spring Boot-Kotlin, например, spring-boot.kotlin_module , spring-context.kotlin_module , и так далее.

Файлы конфигурации Service Loader

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

Плагин Spring Boot

Плагин Spring Boot использует совершенно другой подход. Он не объединяет ресурсы из JAR по отдельности; он добавляет зависимые JAR по мере их появления в uber JAR. Для загрузки классов и ресурсов он предоставляет специальный механизм. Очевидно, что он предназначен для проектов Spring Boot.

Настройка плагина Spring Boot проста:

Давайте проверим структуру финального JAR:

Скомпилированные классы проекта

Загрузка классов в Spring Boot

Вот выдержка из манифеста по образцу проекта:

Как вы можете видеть, главный класс является специфичным классом Spring Boot, в то время как "настоящий" главный класс упоминается в другой записи.

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

Заключение

В этой статье мы описали 3 различных способа создания самодостаточных исполняемых JAR:

Assembly хорошо подходит для простых проектов

Когда проект становится более сложным и вам нужно работать с дублирующимися файлами, используйте Shade

Наконец, для проектов Spring Boot лучше всего использовать специальный плагин.

Полный исходный код этой статьи можно найти на Github в формате Maven.

Материалы для дополнительного изучения:

Что такое «хороший код» — это во многом спорная тема. Кто-то скажет, что если код работает, значит он достаточно хорош. Кто-то обязательно добавит, что код должен быть легок в понимании и сопровождении. А кто-то добавит, что код еще обязательно должен быть быстрым. Об этом уже много написано и сказано. Что же, давайте еще раз поговорим на эту интересную и холиварную тему. Регистрируйтесь на онлайн-интенсив

Перевод подготовлен в рамках курса "Java Developer. Basic"

Читайте также: