Перетворюємо Java/JVM додаток в демона

чи Часто ви пишіть shell скрипт і пакетний файл для запуску свого jvm додатки, а як часто копіюєте з іншого проекту?



Можна скористатися 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[])

Можете подивитися скрінкасти з прикладом створення і роботи демона.



Створити демон і скрипти для складання програми за допомогою всього лише однієї команди.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.