JAR-файл Java
JAR — ZIP-архив с .class, resources и metadata в META-INF. Он может быть library или executable artifact.
Структура
demo.jar
├── META-INF/
│ └── MANIFEST.MF
├── com/example/Main.class
└── application.propertiesПросмотр:
jar tf target/demo.jar
unzip -p target/demo.jar META-INF/MANIFEST.MFДля обычного executable JAR manifest содержит:
Main-Class: com.example.MainЗапуск:
java -jar target/demo.jarНаличие Main-Class не упаковывает dependencies автоматически. Возможны:
- thin JAR плюс отдельный classpath;
- shaded/uber JAR со скопированными dependencies;
- framework-specific executable JAR с собственным launcher/layout;
- modular JAR с
module-info.class.
Classpath
При java -jar пользовательский -cp не применяется как при обычном запуске main-класса; classpath может задаваться manifest или launcher. Поэтому команды java -cp ... Main и java -jar ... не взаимозаменяемы.
Resources внутри JAR читаю через classloader:
try (InputStream in =
Main.class.getResourceAsStream("/application.properties")) {
// read resource
}Файловый путь src/main/resources/... после packaging не существует.
Типичные сбои
no main manifest attribute— не задан executable entry point.ClassNotFoundException— dependency не попала в runtime classpath.- Дубли файлов
META-INF/servicesпотеряны при наивной shade-сборке. - Resource ищут как обычный файл относительно working directory.
- Подписанный JAR изменили после signature.
Вопросы для собеседования
Является ли любой JAR исполняемым? Нет; library JAR может не иметь main class.
Почему JAR является ZIP, но не просто архивом исходников? Обычно он содержит bytecode, resources и Java-specific metadata.
Что делает manifest? Хранит metadata, в том числе entry point и дополнительные атрибуты.
Как читать resource из JAR? Через classloader/resource API, а не предполагаемый source path.