Вкратце о решаемой проблеме: Есть исходный код на языке Java, который требует дополнительных библиотек для выполнения. Требуемый результат: Один исполняемый jar архив, содержащий внутри все зависимости. В среде Eclipse есть такая функциональность ("File->Export->Runnable Jar File"), но задача требует этот процесс автоматизировать. Это мое первое знакомство с инструментом Ant, поэтому пишу все очень подробно, для того, чтобы человек с таким же уровнем мог разобраться в этом быстрее, чем это сделал я.
Нам понадобится
Также можете скачать все необходимые файлы примера, который мы тут рассматриваем (ссылочка). Сюда также включен "One-jar library" - так что его отдельно можно не скачивать.
Итак, приступим. Начнем с структуры проекта:
.|-- build --- Сюда будем компилить классы и здесь же поместим полученную программу|-- buildFatJar.xml --- ant script, описывающий весь необходимый нам процесс|-- lib --- директория, содержащая библиотеки, используемые нашей программой| |-- slf4j-api-1.5.11.jar| `-- slf4j-simple-1.5.11.jar|-- one-jar-ant-task-0.96.jar --- эта библиотека предназначена для Ant, дает возможность включать архивы библиотек в архив собственной исполняемой программы`-- src --- папка с исходными кодами`-- by`-- sokol`-- labs`-- ant`-- LibDependentUtil.java --- Класс, содержащий "main" method и использующий дополнительные библиотеки (import org.slf4j.*; )
Файлы исходного кода и библиотеки можно скачать одним архивом, перейдя по всё той же ссылке . И самое интересное, Ant script:
<project name="BuildFatJar" basedir="." default="main"><!-- Импорт дополнительных задач к Ant для создания --><!-- исполняемых jar файлов с включенными зависимостями --><import><javaresource name="one-jar-ant-task.xml"><classpath location="one-jar-ant-task-0.96.jar" /></javaresource></import><!-- Директория с исходными кодами программы --><property name="src.dir" value="src" /><!-- Путь, куда будет скомпилировано приложение --><property name="build.dir" value="build" /><!-- Сюда будет помещен полученный jar --><property name="jar.dir" value="${build.dir}" /><!-- Здесь находятся необходимые библиотеки --><property name="lib.dir" value="lib"/><!-- В эту папку будут помещены скомпилированные классы --><property name="classes.dir" value="${build.dir}/classes" /><!-- Имя создаваемого исполняемого архива --><property name="jarname" value="FatJarExample" /><target name="clean"><delete dir="${build.dir}" /></target><target name="compile"><mkdir dir="${classes.dir}" /><!-- Путь к необходимым библиотекам --><path id="classpath"><fileset dir="${lib.dir}" includes="**/*.jar, **/*.zip" /></path><javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath" /></target><!-- Создаем исполняемый jar с включенными зависимостями --><target name="jar" depends="compile"><property name="main-class" value="by.sokol.labs.ant.LibDependentUtil" /><property name="manifest.file" value="MANIFEST.MF" /><!-- Этот файл будет использоваться для того, чтобы сделать результат исполняемым --><manifest file="${manifest.file}" id="manifest"><!-- Этот аттрибут не следует изменять --><attribute name="Main-Class" value="com.simontuffs.onejar.Boot" /><!-- Здесь указываем путь к точке запуска программы (класс, содержащий "main" method) --><!-- ${main-class} ссылается на значение определенное в начале данного скрипта --><attribute name="One-Jar-Main-Class" value="${main-class}" /></manifest><mkdir dir="${jar.dir}" /><!-- Эта дополнительная задача загружается из one-jar-ant-task-0.96.jar --><!-- Для ее загрузки используем импорт в начале данного скрипта --><one-jar destfile="${jar.dir}/${jarname}.jar" manifest="${manifest.file}"><main><!-- Скомпилированные классы вашего приложения --><fileset dir="${classes.dir}" /></main><lib><!-- Путь к необходимым библиотекам --><fileset dir="${lib.dir}" /></lib></one-jar><delete file="${manifest.file}" /></target><target name="delete_classes"><delete deleteonexit="true" dir="${classes.dir}" /></target><target name="build_app" depends="compile,jar,delete_classes" /><target name="main" depends="clean,build_app" /></project>
Финал! Собираем, для чего открываем терминал, переходим в директорию проекта и пишем: "ant -f buildFatJar.xml", читаем сообщение "BUILD SUCCESSFUL" и запускаем полученное приложение "java -jar build/FatJarExample.jar". Thats all!
Немного комментариев:
1) Почему нельзя просто запихнуть необходимые библиотеки в целевой архив?
Стандартный загрузчик классов не производит поиск в архивах, вложенных в другие архивы. Для этого и нужна библиотека "one-jar-ant-task-0.96.jar" - она предоставляет специальные загрузчик классов, который справляется с этой задачей. Одним из вариантов альтернативного решения будет распаковать необходимые библиотеки в папку с классами вашего приложения, после чего это все собирается как единый проект. Не пробовал, но уверен, что должно получиться.
2) Почему обязательно Ant 1.8?
Необязательно, Но в нем есть очень удобный способ загрузки новых задач
<import><javaresource name="one-jar-ant-task.xml"><classpath location="one-jar-ant-task-0.96.jar" /></javaresource></import>