Часто ли вы пишите shell скрипт и пакетный файл для запуска своего jvm приложения, а как часто копируете из другого проекта?
Можно воспользоваться appassembler-maven-plugin для генерации скриптов запуска нашей программы и создания из нее демона. Плагин делает всю рутинную работу по конфигурации java service wrapper, генерации скриптов и сборке приложения за нас.
Но мы упростим нашу жизнь и воспользуемся автоматизированным решением для создание скелета maven артефактов для сборки своих демонов. Плагином-генератором com.github.igor-suhorukov:daemon-archetype для maven, который доступен в центральном репозитарии и на github. И под капотом все равно appassembler-maven-plugin!
Все что надо сделать для создания скелета демона — выполнить команду создания в интерактивном режиме, а затем сконфигурировать что получилось под проект:
Важное замечание! Демон java service wrapper останавливается сигналом SIGINT, поэтому для корректного освобождения ресурсов надо зарегистрировать свой Runtime.getRuntime().addShutdownHook(...).
Параметры groupId, artifactId, version не заслуживают особого внимания, так как они требуются любым archetype плагином и это то, что будет в соответствующих тегах pom.xml.
Параметром entry-point-class нужно указать полностью квалифицированное имя класса, метод public static void main(String[]) которого демон будет вызывать при старте. В случае java приложения можно указать класс с методом main как из зависимости проекта main-artifact*, так и из директории src/main/java текущего проекта.
Параметры main-artifact-artifactId, main-artifact-groupId, main-artifact-version указывают на зависимость, которая содержит entry-point-class. В сборку пакуются также транзитивные зависимости для main-artifact*.
launcher-name определяет имя скрипта демона в директории bin.
Для пробы создадим демон запуска git сервера. Выполнив в консоли команду, либо указав те же параметры в интерактивном режиме:
После отредактируем получившийся pom.xml, добавив в теги program и daemon следующий фрагмент конфигурации:
Выполняем команду:
После сборки в директории target будет архив с демоном: gitblit-launcher-1.0-SNAPSHOT-daemon.tgz и два архива в формате tgz и zip с обычными скриптами для запуска консольного приложения gitblit-launcher-1.0-SNAPSHOT-assembly.tgz, gitblit-launcher-1.0-SNAPSHOT-assembly.zip.
В нашем примере в сборку с демоном упакуется jar файл из com.github.igor-suhorukov:groovy-grape-aether:2.4.5.4. Демон запустит JVM с указанием main класса com.github.igorsuhorukov.groovy.GroovyMain и передаст ему параметром путь к Groovy скрипту raw.githubusercontent.com/igor-suhorukov/git-configuration/master/gitblit.groovy.
Groovy скрипт скачивает gitblit.war из репозитария проекта, распаковывает его в домашнюю директорию пользователя и заменяет в конфигурации gitblit путь к хранилищу репозитариев. После этого запускает jetty сервер и gitblit внутри него.
Можете посмотреть скринкаст с примером создания и работы демона.
Создать демон и скрипты для сборки приложения можно с помощью всего лишь одной команды.
Можно воспользоваться appassembler-maven-plugin для генерации скриптов запуска нашей программы и создания из нее демона. Плагин делает всю рутинную работу по конфигурации java service wrapper, генерации скриптов и сборке приложения за нас.
Но мы упростим нашу жизнь и воспользуемся автоматизированным решением для создание скелета maven артефактов для сборки своих демонов. Плагином-генератором com.github.igor-suhorukov:daemon-archetype для maven, который доступен в центральном репозитарии и на github. И под капотом все равно appassembler-maven-plugin!
Все что надо сделать для создания скелета демона — выполнить команду создания в интерактивном режиме, а затем сконфигурировать что получилось под проект:
mvn archetype:generate -DarchetypeGroupId=com.github.igor-suhorukov -DarchetypeArtifactId=daemon-archetype -DarchetypeVersion=0.1
Важное замечание! Демон java service wrapper останавливается сигналом SIGINT, поэтому для корректного освобождения ресурсов надо зарегистрировать свой Runtime.getRuntime().addShutdownHook(...).
Конфигурация плагина daemon-archetype.
Параметры groupId, artifactId, version не заслуживают особого внимания, так как они требуются любым archetype плагином и это то, что будет в соответствующих тегах pom.xml.
Параметром entry-point-class нужно указать полностью квалифицированное имя класса, метод public static void main(String[]) которого демон будет вызывать при старте. В случае java приложения можно указать класс с методом main как из зависимости проекта main-artifact*, так и из директории src/main/java текущего проекта.
Параметры main-artifact-artifactId, main-artifact-groupId, main-artifact-version указывают на зависимость, которая содержит entry-point-class. В сборку пакуются также транзитивные зависимости для main-artifact*.
launcher-name определяет имя скрипта демона в директории bin.
Пример: демон git сервера gitblit.
Для пробы создадим демон запуска git сервера. Выполнив в консоли команду, либо указав те же параметры в интерактивном режиме:
mvn archetype:generate -DarchetypeGroupId=com.github.igor-suhorukov -DarchetypeArtifactId=daemon-archetype -DarchetypeVersion=0.1 -DgroupId=com.github.igor-suhorukov -DartifactId=gitblit-launcher -Dversion=1.0-SNAPSHOT -Dpackage=com.github.igor-suhorukov -Dentry-point-class=com.github.igorsuhorukov.groovy.GroovyMain -Dlauncher-name=launcher -Dmain-artifact-artifactId=groovy-grape-aether -Dmain-artifact-groupId=com.github.igor-suhorukov -Dmain-artifact-version=2.4.5.4 -DinteractiveMode=false
После отредактируем получившийся pom.xml, добавив в теги program и daemon следующий фрагмент конфигурации:
<commandLineArguments>
<commandLineArgument>https://raw.githubusercontent.com/igor-suhorukov/git-configuration/master/gitblit.groovy </commandLineArgument>
</commandLineArguments>
Выполняем команду:
mvn package
После сборки в директории target будет архив с демоном: gitblit-launcher-1.0-SNAPSHOT-daemon.tgz и два архива в формате tgz и zip с обычными скриптами для запуска консольного приложения gitblit-launcher-1.0-SNAPSHOT-assembly.tgz, gitblit-launcher-1.0-SNAPSHOT-assembly.zip.
В нашем примере в сборку с демоном упакуется jar файл из com.github.igor-suhorukov:groovy-grape-aether:2.4.5.4. Демон запустит JVM с указанием main класса com.github.igorsuhorukov.groovy.GroovyMain и передаст ему параметром путь к Groovy скрипту raw.githubusercontent.com/igor-suhorukov/git-configuration/master/gitblit.groovy.
Groovy скрипт скачивает gitblit.war из репозитария проекта, распаковывает его в домашнюю директорию пользователя и заменяет в конфигурации gitblit путь к хранилищу репозитариев. После этого запускает jetty сервер и gitblit внутри него.
gitblit.groovy
import com.github.igorsuhorukov.smreed.dropship.MavenClassLoader
@Grab(group='org.codehaus.plexus', module='plexus-archiver', version='2.10.2')
import org.codehaus.plexus.archiver.zip.ZipUnArchiver
@Grab(group='org.codehaus.plexus', module='plexus-container-default', version='1.6')
import org.codehaus.plexus.logging.console.ConsoleLogger
@Grab(group = 'org.eclipse.jetty', module = 'jetty-runner', version = '9.3.7.RC1' )
import org.eclipse.jetty.runner.Runner
def gitblit = new File(MavenClassLoader.using('http://gitblit.github.io/gitblit-maven').resolveArtifact('com.gitblit:gitblit:war:1.7.1').getFile())
File gitblitDirectory = new File(System.getProperty('user.home'), gitblit.getName().replace('.war',''))
if(!gitblitDirectory.exists()){
gitblitDirectory.mkdir()
ZipUnArchiver unArchiver = new ZipUnArchiver()
unArchiver.setSourceFile(gitblit)
unArchiver.enableLogging(new ConsoleLogger(ConsoleLogger.LEVEL_DEBUG,"Logger"))
unArchiver.setDestDirectory(gitblitDirectory)
unArchiver.extract()
def dataPath = new File(System.getProperty('user.home'), '.gitblit_data')
if(!dataPath.exists()){ dataPath.mkdir() }
def webXml = new File(gitblitDirectory.getAbsoluteFile(), 'WEB-INF/web.xml')
webXmlText = webXml.text
webXml.withWriter { w -> w << webXmlText.replace('${contextFolder}/WEB-INF/data', dataPath.getAbsolutePath()) }
}
Runner.main([gitblitDirectory] as String[])
Можете посмотреть скринкаст с примером создания и работы демона.
Создать демон и скрипты для сборки приложения можно с помощью всего лишь одной команды.