Что такое исполняемый файл в java
Войти
Авторизуясь в LiveJournal с помощью стороннего сервиса вы принимаете условия Пользовательского соглашения LiveJournal
Философия, стратегия, размышления, заметки (раньше про Excel/VBA, Python и пр.)Исполняемый JAR файл из Eclipse
JAR (Java ARchive) - это Java-архив, который позволяет хранить в одном архивном файле все ресурсы Java-проекта. JAR-файлы делятся на две категории:
1) простые JAR-файлы
2) исполняемые JAR-файлы
У последних есть одна приятная особенность - в WinXP их можно запустить двойным щелчком мыши по значку.
В Eclipse существует специальная функция экспорта, которая позволяет быстро и без особого труда создавать исполняемые JAR-файлы. Допустим, мы создали некий тестовый проект. Вот как он выглядит в Eclipse:
Вот текст класса "Hello":
public class Hello Hello( String msg)
// Create a new JFrame container.
JFrame jfrm = new JFrame( "A Simple Swing Application" );
// Give the frame an initial size.
jfrm.setSize(275, 100);
// Terminate the program when the user closes the application.
jfrm.setDefaultCloseOperation(JF rame.EXIT_ON_CLOSE);
// Create a text-based label.
JLabel jlab = new JLabel(msg);
// Add the label to the content pane.
jfrm.add(jlab);
// Display the frame.
jfrm.setVisible( true );
>
public static void main( String args[])
SwingUtilities.invokeLater( new Runnable() <
public void run() <
new Hello( "Hello, world!" );
>
>);
>
>
Смысл в том, чтобы программа создала swing-frame и вывела туда волшебные слова "Hello, world!"
Дальше в разделе File выбираем строку Export. и в появившемся окошке выбираем опцию Runnable JAR file:
Следующим шагом необходимо определить спецификацию JAR-файла:
Вот тут мне пришлось немного повозиться с Launch configuration. Эта строка будет у вас пустой, пока вы не наведете мышку на свой Java-проект (у меня это проект mytests) и не откроете правой клавишей мыши контекстное меню, где вам надо будет выбрать Debug As -> Dubug Configuration:
Когда ваше программное приложение выходит за пределы десятка строк кода, вам, вероятно, следует разделить код на несколько классов. На этом этапе встает вопрос о том, как их распределить. В 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"
Сборка (англ. assembly) — двоичный файл, содержащий исполняемый код программы или (реже) другой подготовленный для использования информационный продукт.
Автоматизация сборки — этап написания скриптов или автоматизация широкого спектра задач применительно к ПО, применяемому разработчиками в их повседневной деятельности, включая такие действия, как:
1. компиляция исходного кода в бинарный код
2. сборка бинарного кода
3. выполнение тестов
4. разворачивание программы на производственной платформе
5. написание сопроводительной документации или описание изменений новой версии
Для автоматизации сборки проектов традиционно используют системы сборки, такие как make на Unix подобных системах и nmakeдля компилятора Microsoft. Также традиционно написание файлов для сборки проекта под эти системы является задачей нетривиальной. Конечно, пользуясь только Mictosoft Visual Studio можно даже не подозревать о существовании этих файлов, так как интегрированная среда разработки достаточно удобно скрывает всю схему работы, оставляя снаружи несколько диалоговых окон и кнопку Build. Но для сложных проектов использующих массу сторонних библиотек и кроссплатформенных проектов такой подход часто оказывается неприемлемым.
Простой пример make-файл построен "традиционным" способом. Все исходные файлы собираемой программы находятся в одном каталоге:
Makefile
Предполагается, что для компиляции программы используется компилятор GCC, и объектные файлы имеют расширение ".o". Пример make-файл:
iEdit: main.o Editor.o TextLine.o
main.o: main.h Editor.hTextLine.h
Первое правило заставляет make перекомпоновывать программу при изменении любого из объектных файлов. Второе правило говорит о том, что объектные файлы зависят от соответствующих исходных файлов. Каждое изменение файла с исходным текстом будет вызывать его перекомпиляцию. Следующие несколько правил указывают, от каких заголовочных файлов зависит каждый из объектных файлов. Данный пример не использует ни одной функции из набора make, он не оптимальный (зачем перекомпилировать и пересобрать всё при изменении 1го файла) и громоздкий, за то простой и наглядный. При вызове make, будет взято 1е правило. Правила допускают рекурсии, поэтому написания доброкачественного (чтоб сборщик не умер в вечном цикле) make-файла, ложиться на плечи разработчика.
2. Принципы сборки в java
2.1. Как работает java компилятор
Текст программы — это исходный код программы на языке java.
Дополнения — это классы, которые необходимо учитывать во время сборки (библиотеки).
В итоге мы получаем набор файлов с расширением class. То есть, если мы используем сторонние библиотеки – мы должны указать их при сборке. Это могут быть скомпилированные классы или собранные подсистемы.
Не всегда для компиляции необходимо указывать дополнительные библиотеки (к примеру, если у нас программа в 1 программный файл). Но если всё же это необходимо, то для этого компилятор java необходимо запустить с аргументом «-cp» (сокращение от --classpath). После этого аргумента идёт список библиотек (jar файлов или файлов class) разделённых символом разделителем файлов (в *nix это «:», в windows это «;»).
Пример компиляции программы из одного файла:
javacHelloWorld.java
Пример компиляции программы c дополнительными библиотеками «myLib» и «my2ndLib»:
javac -cp myLib.jar:my2ndLib.jar NotStandartHelloWorld.java
В java нет разграничения между собранной библиотекой, исполняемым приложением или же подсистемой. Что имеется в виду, что если вы хотите создать самостоятельную сущность в едином файле, вы создаёте jar файл. К примеру, если вы создаёте библиотеку, то это будет jar файл с набором классов, который могут быть использованный другими разработчиками, если это подсистема, то это часть функционала (набор классов) вынесенная за рамки основного модуля, но используемая в нём (что то вроде частной библиотеки), и т.д..
2.2. Выполнение java-программы.
Выполнение классов работает схожим образом с компиляцией (используются даже те же аргументы).
Если после компиляции у нас получилось 10 классов, то выполняем только класс который содержит функцию main, остальные классы должны быть представлены как библиотеки.
К примеру, запуск программы c дополнительными библиотекой «sout», которая находиться в папку «lib» выглядеть так:
java -cp lib/sout.jar HelloWorld
По умолчанию, все классы в текущем каталоги включены в пути (-cp для классов в текущем каталоге указывать не надо). Что имеется в виду, если мы скомпилировали программу, и в итоге получили множество классов в одной папке, то мы можем запускать только лишь главный класс, остальные классы java попробует найти сама в текущем каталоге (Даже если они находятся во вложенных папках, java и туда заглянет).
Такой подход допустим, когда у нас немного классов, но при больших системах перечисление всех классов не возможно (их количество может превышать тысячи …). Поэтому можно выполнять не класс, а специально собранный jar-файл. Для этого необходимо указать аргументы -jar.
java -cp lib.jar -jar myApp.jar
Jar-файл — это ZIP архив (то есть вы можете разархивировать его). Jar-файл должен в себе содержать набор классов и файл META-INF/MANIFEST.MF, в котором описаны характеристики данного jar-файла.
Основной вариант создания Jar-файла:
jar cf jar-file input-file(s)
Jar – это утилита и набора утилит которые вы получаете при установке java.
Программа jar принимает аргументы в old-UNIX стиле: вначале идут ключи потом аргументы программы, ключ с аргументом указывается последним, не указывать «-» перед аргументами, группировать короткие аргументы («cf» значит «-c -f »).
1. Опция c — говорит о том, что вы хотите создать (create) jar-файл.
2. Опция f — говорит о том, что вы хотите создать файл (file) с определённым именем (при выполнении данного примера создастся файл с именем «jar-file.jar»).
3. Аргумент input-file(s) является разделенный пробелами список из одного или нескольких файлов, которые вы хотите включить в ваш JAR-файл. input-file(s) аргумент может содержать символ «*». Если любой из входных является каталогом, содержимое этих каталогов добавляются в архив JAR рекурсивно.
Когда вы создаете JAR-файл, он автоматически получает файл манифеста по умолчанию (если вы его не указали во входных файлах – он будет создан автоматически). В jar-файле может быть только один файл манифеста с указанным путём:
Общая структура манифеста имеет вид:
Заголовок: значение
Все символы пробелов (\n, \r, \t, …) в «значении» будут удалены, к примеру, манифест:
Для создания и редактирования исходного кода Java вы можете использовать любой текстовый редактор или IDE. Этот раздел демонстрирует, как создавать, компилировать и запускать программы Java из командной строки. В разделе «Компиляция и запуск Java программ в NetBeans» показано, как это делать в IDE на примере NetBeans.
Можно вообще обойтись без IDE, а писать исходный код в любом текстовом редакторе (например, в Notepad), а компилировать в командной строке.
Внимание: файл с исходным кодом должен иметь расширение .java и иметь в точности такое же имя, как и имя публичного (public) класса. Например, файл с исходным кодом:
должен называться Welcome.java, поскольку имя public класса – Welcome.
Компилятор Java преобразовывает файл с исходным кодом Java в файл с байткодом Java. Следующая команда компилирует Welcome.java:
Если нет синтаксических ошибок, компилятор генерирует файл байкода с расширением .class. Следовательно, приведённая выше команда генерирует файл с названием Welcome.class.
Чтобы иметь возможность компилировать и запускать программы, вы должны установить JDK. Как это сделать описано в инструкциях:
Язык Java – это высокоуровневый язык программирования, но байткод Java – это низкоуровневый язык. Байткод похож на машинные инструкции, но нейтрален к архитектуре (не зависит от архитектуры) и может запускаться на любой платформе, которая имеет виртуальную машину Java – Java Virtual Machine (JVM). В отличие от физической машины, виртуальная машина – это программа, которая интерпретирует байткод Java. Это одно из главных преимуществ Java: байткод Java может работать на различных аппаратных платформах и операционных системах. Исходный код Java компилируется в байткод Java, а байткод Java интерпретируется виртуальной машиной Java. Ваш код Java может использовать код библиотеки Java. JVM выполняет ваш код вместе с кодом из библиотеки.
Выполнить Java программу – это значит запустить байткод программы. Вы можете выполнить байткод на любой платформе с JVM, которая является интерпретатором. Она (виртуальная машина Java) переводит отдельные инструкции байткода в целевой машинный языковой код. Это делается последовательно – одна инструкция за раз, а не вся программ за один присест. Каждый шаг немедленно выполняется, сразу после перевода.
Следующая команда выполняет байткод для программы, которая приведена выше:
На скриншоте ниже показан процесс компиляции и запуска:
Внимание: не используйте расширение .class в команде, когда запускаете программу. Используйте ИмяКласса для запуска программы. Если вы в командной строке используете ИмяКласса.class, то система будет пытаться работать с файлом ИмяКласса.class.class.
Справка: когда выполняется Java программа, JVM начинает с загрузки байткода класса в память, используя программу под названием загрузчик классов (class loader). Если ваша программа использует другие классы, загрузчик классов динамически подгружает их перед тем, как они понадобятся. После загрузки класса, JVM использует программу под названием контролёр байткода (bytecode verifier) для проверки правильности байткода и проверки, что байткод не нарушает ограничений безопасности Java. Java обеспечивает строгую защиту, чтобы убедиться, что файлы классов Java не подделаны и не вредят вашему компьютеру.
Педагогическое примечание: ваш инструктор может требовать от вас использовать пакеты для организации программ. Например, все программы из этой части можно поместить в пакет chapter2. Подробности о пакетах и пространствах имён будут рассмотрены далее. Также посмотрите раздел «Почему NetBeans всегда использует package».
Типичные ошибки компиляции и запуска Java программ
Команда javac не найдена
Если при запуске javac, т.е. при попытке компиляции Java программы вы получаете ошибку:
Это означает, что JDK не установлен. Либо установлен, но не настроены переменные окружения. Способы исправления очевидны:
- установить JDK
- настроить переменные окружения
Если JDK установлен, то можно обойтись без добавления переменной окружения. Для этого используйте абсолютный путь до исполнимого файла javac:
Ошибка Class names are only accepted if annotation processing is explicitly requested
Если попытаться скомпилировать программу следующим образом:
то возникнет ошибка:
Причина ошибки в том – что вы забыли указать расширение файла .java.
Ошибка записи (error while writing)
Компиляция заканчивается ошибкой:
Причина ошибки в том, что у компилятора (javac) недостаточно прав на запись в тот каталог, куда он пытается сохранить новый файл .class. Чтобы ошибка исчезла: предоставьте компилятору дополнительные права (запустите от имени администратора), либо сохраняйте в папку, на которую у текущего пользователя имеются права записи.
Ошибка «class is public, should be declared in a file named»
который заканчивается примерной такой ошибкой
означает, что вы неправильно назвали класс в исходном коде программы. Имя класса должно совпадать с именем файла. В данном случае файл называется Welcome.java, а класс внутри программы назван Welcomee
Error: Could not find or load main class
Если попытаться запустить программу следующим образом:
то возникнет ошибка
Причина её в том, что не нужно было добавлять к названию файла расширение .class. Виртуальная машина автоматически добавляет расширение и в приведённом примере она ищет файл Welcome.class.class
Ошибка Error: Could not find or load main class при запуске Java программы по абсолютному пути
Эта ошибка возможно при запуске Java программы по абсолютному пути:
Ошибка возникает как в Windows, так и в Linux:
Если в терминале вы находитесь в той же директории, что и файл, который вы запускаете, то не нужно указывать абсолютный путь. Например, нужно запускать так:
Если же вы находитесь в другой директории, то нужно использовать опцию -cp, после которой указать путь до каталога, где размещена запускаемая программа. А далее указать запускаемый файл без расширения .class:
Как видно из скриншота, командная строка находится в папке C:\WINDOWS\system32. Файл, который нам нужно запустить, находится в папке C:\ (корень диска). Мы указываем после ключа -cp папку C:\, а затем пишем имя файла программы без расширения – Welcome.
Аналогично нужно поступать в Linux. Пример команды:
Ошибка Main method not found in class
Если при запуске вы столкнулись с ошибкой:
Это означает, что вы не указали метод main, либо написали слово неправильно (например, Main вместо main).
Особенности компиляции и запуска Java программ в Windows
Команда "javac" не является внутренней или внешней командой, исполняемой программой или пакетным файлом
Эта ошибка рассмотрена чуть выше. Для установки и настройки переменных окружения в Windows обратитесь к инструкции «Установка Java (JDK) в Windows».
Проблема с кодировкой в Java программах в командной строке Windows
Если вы написали программу, которая выводит кириллицу в консоль:
А в качестве результата получили крякозяблы:
Значит кодировка, в которой выводит строки ваша программа, отличается от кодировки командной строки Windows.
Для того, чтобы смена кодировки командной строки Windows не сбрасывалась после закрытия и открытия командной строки, можно внести изменения в реестр Windows. Для этого нажмите Win+x, выберите «Выполнить», в открывшееся окно введите regedit. В открывшейся программе (редактор реестра Windows) перейдите к [HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\Autorun] и измените (или добавьте) значение на @chcp 65001>nul
Читайте также: