In this blog post, I show you how to install a Java application with WinSW as a Windows service. WinSW is an executable binary, which can be used to wrap and manage any custom process as a Windows service.
Demo ¶
First, we need a demo application. I will use a simple Quarkus application for this purpose. You can install any Java application as a service. Usually, you install applications that run continuously, like an HTTP server in this case.
To bootstrap a Quarkus application, run this command:
mvn io.quarkus:quarkus-maven-plugin:2.5.1.Final:create -DprojectGroupId=com.testlab -DprojectArtifactId=testservice -DclassName="com.testlab.testservice.GreetingResource" -Dpath="/hello"
cd testservice
We will use the application as is, with just a small change. I want to create a fat JAR, a JAR with all dependent libraries included. You can package your application in any way you want. In this case, I prefer the fat JAR installation because I only have to copy one file.
Open src\main\resources\application.properties
and insert the following property:
quarkus.package.type=uber-jar
Now you can package the application with .\mvnw.cmd package
. You will find the JAR
in the target folder: testservice-1.0.0-SNAPSHOT-runner.jar
.
Preparation ¶
You can proceed in different ways. I usually create a new folder where I copy all the files needed to
run the application as a service. Copy the JAR from the target
folder into this directory.
Java ¶
Next, I download the Java Runtime and also copy it into this folder. This is optional. Your service can access a globally installed Java. But I prefer to have everything contained in one folder and not have to worry about someone updating or removing the globally installed Java.
I usually download Java from Adoptium. On the release page, you will find the ZIP file with the JDK for Windows.
Download the ZIP file and unzip it into the install folder. I unzip it into the java
subfolder, so the java.exe
is accessible with this path java\bin\java.exe
.
WinSW ¶
Open the release page of the WinSW project and download the executable suitable for your platform.
https://github.com/winsw/winsw/releases
For this demo installation, I will download WinSW.NET461.exe
. WinSW runs on Windows with .NET Framework 2.0, 4.0, or 4.6.1. If you need to install
the service on a Windows system without the .NET framework, download the core variant WinSW-x64.exe
for 64-bit or WinSW-x86.exe
for 32-bit systems.
Copy the executable into the folder where your JAR resides. Rename the WinSW executable to any name you like.
For this example, I will rename it to testservice.exe
. Create an XML file with the same base name: testservice.xml
.
Make sure that the EXE and XML files are located in the same folder.
Open the XML file and paste the following code into it:
<service>
<id>testservice</id>
<name>Test Service</name>
<description>This is a test service.</description>
<executable>"%BASE%\java\bin\java"</executable>
<arguments>-jar "%BASE%\testservice-1.0.0-SNAPSHOT-runner.jar"</arguments>
<logmode>rotate</logmode>
<stopparentprocessfirst>true</stopparentprocessfirst>
</service>
Check the executable path and arguments. %BASE%
is an environment variable that points to the directory where the WinSW executable is located.
If you want to start the application with a Java that is on the %PATH%
, just use <executable>java</executable>
.
Relevant here is <stopparentprocessfirst>
. This tells WinSW to shut down the parent process first. In our case, this is useful
because the main process opens a console (java
), which can respond to Ctrl+C and will gracefully shutdown the child process (the Java application).
Check out this wiki page to learn more about all the supported options:
https://github.com/winsw/winsw/blob/master/doc/xmlConfigFile.md
Directory structure ¶
The directory structure of my install folder:
testservice.exe
testservice.xml
testservice-1.0.0-SNAPSHOT-runner.jar
java
bin
java.exe
...
conf
legal
lib
...
Installation ¶
With everything in place, you can install the Windows service with this command:
testservice.exe install
The WinSW command supports the following options:
install
: Install the serviceuninstall
: Uninstall the servicestart
: Start the installed servicestop
: Stop the servicerestart
: Restart the servicestatus
: Show the current service status (NonExistent, Started, Stopped)
The service by default is installed with start mode Automatic
. That means Windows starts
the service when it boots up. You can change that with the <startmode>
configuration in the XML file.
<startmode>Manual</startmode>
To test the installation, open http://localhost:8080
in a browser. You should see the default start page of Quarkus.
To test if the graceful shutdown works, stop the service:
testservice stop
Open the file testservice.out.log
.
2020-05-06 05:30:52,501 INFO [io.quarkus] (main) Profile prod activated.
2020-05-06 05:30:52,501 INFO [io.quarkus] (main) Installed features: [cdi, resteasy]
2020-05-06 05:30:54,801 INFO [io.quarkus] (main) testservice stopped in 0.032s
We see that the application shutdown gracefully because of the testservice stopped
log entry.
Note that WinSW creates by default three log files:
<service>.out.log
: Console output from the application (System.out.println
)<service>.err.log
: Error output from the application (System.err.println
)<service>.wrapper.log
: Log output from WinSW itself
That concludes this tutorial about installing any Java applications as a Windows Service.
Optionally, you could try and create a native image of your application with
GraalVM.
The service installation does not change much. You don't need the JRE
anymore and have to change <executable>
accordingly.