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.

См. Артефакт, Основы иcпользования Maven, Class loader.