Escolar Documentos
Profissional Documentos
Cultura Documentos
EverwonderedhowtoinstallaJavaapplicationasaWindowsservice?Thisarticleshows
youhowtodoit.
by
BozhidarBozhanov
Jun.27,16JavaZone
Like(18)
Save
11.03kViews
LearnmoreaboutKotlin,anewprogramminglanguagedesignedtosolveproblemsthatsoftwaredevelopers
faceeverydaybroughttoyouinpartnershipwithJetBrains.
Itsoundslikesomethingyoudneverneed,butsometimes,whenyoudistributeendusersoftware,youmay
needtoinstallajavaprogramasaWindowsservice.IhadtodoitbecauseIdevelopedatoolforcivilservants
toautomaticallyconvertandpushtheirExcelfilestotheopendataportalofmycountry.Thetoolhastorun
periodically,soitsaprimecandidateforaservice(whichwouldmaketheuploadpossibleevenifthecivil
servantforgetsaboutthistaskaltogether,andbesides,repetitivemanualuploadisawasteoftime).
EventhoughtherearenumerouspostsandStackOverflowanswersonthetopic,itstilltookmealotoftime
becauseofminorcaveatsandoneimportantprerequisitethatfewpeopleseemedtohavehavingabundled
JRE,sothatnobodyhastodownloadandinstallaJRE(wouldcomplicatetheinstallationprocessunnecessarily,
andthetargetaudienceisnotnecessarilytechsavvy).
So,withmavenprojectwithjarpackaging,Ifirstthoughtofpackagingan.exe(withlaunch4j)andthen
registeringitasaservice.Theproblemwiththatisthatthejavaprogramusesascheduledexecutor,soitnever
exits,whichmakesstartingitasaprocessimpossible.
SoIhadtodaemonizeit,usingcommonsdaemonprocrun.Beforedoingthat,Ihadtoassembleevery
componentneededintoasingletargetfolderthefatjar(includingalldependencies),theJRE,thecommons
daemonbinaries,andtheconfigfile.
Youcanseethefullmavenfilehere.Therelevantbitsare(where${installer.dir}is
${project.basedir}/target/installer}):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>mavencompilerplugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>mavenassemblyplugin</artifactId>
<executions>
<execution>
<id>assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptorRefs>
<descriptorRef>jarwithdependencies</descriptorRef>
</descriptorRefs>
<finalName>opendatackanpusher</finalName>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>mavenantrunplugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>defaultcli</id>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<copytodir="${installer.dir}/jre1.8.0_91">
<filesetdir="${project.basedir}/jre1.8.0_91"/>
</copy>
<copytodir="${installer.dir}/commonsdaemon">
<filesetdir="${project.basedir}/commonsdaemon"/>
</copy>
<copyfile="${project.build.directory}/opendatackanpusher.jar"
todir="${installer.dir}"/>
<copyfile="${project.basedir}/install.bat"todir="${installer.dir}"
/>
<copyfile="${project.basedir}/uninstall.bat"
todir="${installer.dir}"/>
<copyfile="${project.basedir}/config/pusher.yml"
todir="${installer.dir}"/>
<copyfile="${project.basedir}/LICENSE"todir="${installer.dir}"/>
</target>
</configuration>
</execution>
</executions>
</plugin>
Youwillnoticetheinstaller.batanduninstaller.batwhicharethefilesthatusecommonsdaemontomanagethe
service.Theinstallercreatestheservice.Commonsdaemonhasthreemodes:.exe(whichallowsyoutowrap
anarbitraryexecutable),Java(whichislike.exe,butforjavaapplications)andJVM(whichrunsthejava
applicationinthesameprocessIdontknowhowexactlythough).
Icoulduseallthreeoptions(includingthelaunch4jcreated.exe),buttheJVMallowsyoutohaveadesignated
methodtocontrolyourrunningapplication.TheStartClass/StartMethod/StopClass/StopMethodparametersare
forthat.Heresthewholeinstaller.bat:
commonsdaemon\prunsrv//IS//OpenDataPusherDisplayName="OpenDataPusher"
Description="OpenDataPusher"^
Install="%cd%\commonsdaemon\prunsrv.exe"
Jvm="%cd%\jre1.8.0_91\bin\client\jvm.dll"StartMode=jvmStopMode=jvm^
Startup=autoStartClass=bg.government.opendatapusher.Pusher
StopClass=bg.government.opendatapusher.Pusher^
StartParams=startStopParams=stopStartMethod=windowsService
StopMethod=windowsService^
Classpath="%cd%\opendatackanpusher.jar"LogLevel=DEBUG^LogPath="%cd%\logs"
LogPrefix=procrun.log^
StdOutput="%cd%\logs\stdout.log"StdError="%cd%\logs\stderr.log"
commonsdaemon\prunsrv//ES//OpenDataPusher
Afewclarifications:
TheJVMparameterpointstotheJVM.dll(tobehonest,Imnotsureifthiswillworkifthereisnootherjava
installationonthemachineitshould)
TheStartClass/StartMethod/StopClass/StopMethodpointtoadesignatedmethodforcontrollingtherunning
application.Inthiscase,startingwouldjustcallthemainmethod,andstoppingwouldshutdownthe
scheduledexecutor,sothattheapplicationcanexit
Theclasspathparameterpointstothefatjar
Using%cd%isriskyfordeterminingthepathtothecurrentdirectory,butsincetheenduserswillalwaysbe
startingitfromthedirectorywhereitresides,itssafeinthiscase.
ThewindowsServicelookslikethat:
publicstaticvoidwindowsService(Stringargs[])throwsException{
Stringcmd="start";
if(args.length>0){
cmd=args[0];
if("start".equals(cmd)){
Pusher.main(newString[]{});
}else{
executor.shutdownNow();
System.exit(0);
}
Oneimportantnotehereisthe32bit/64bitproblemyoumayhave.Thatswhyitssafertobundlea32bitJRE
andusethe32bit(default)prunsrv.exe.
IthenhadaninstallerfolderwithJREandcommonsdaemonfoldersandtwobatfilesandonefatjar.Icould
thenpackagethatasaselfextractablearchiveanddistributeit(withamanual,ofcourse).IlookedintoIzPack
aswell,butcouldntfindhowtobundleaJRE(maybeyoucan).
ThatsaprettynichescenariousuallywedevelopfordeployingtoaLinuxserver,butprovidinglocaltoolsfor
abigorganizationusingJavamaybeneededeverynowandthen.Inmycasethelongrunningpartwasa
scheduledexecutor,butitcanalsorunajettyservicethatservesawebinterface.Whywoulditdothat,instead
ofprovidingaURLincaseswhereaccesstothelocalmachinematters.Itcanevenbeadistributedsearch
engine(likethat)oranotherp2psoftwarethatyouwanttowriteinJava.
TheJavaZoneisbroughttoyouinpartnershipwithJetBrains.Discoverhowpowerfulstaticcodeanalysisand
ergonomicdesignmakedevelopmentnotonlyproductivebutalsoanenjoyableexperience.