Monday, February 23, 2015
Spring boot 1.4 run as windows service Procrun
The challenge was starting spring boot application as windows service. I spent a long time searching on the Internet the solution but I didn't find it.
My solution was the following.
First I created an application using start.spring.io
Then, I created a project to which I added spring-boot-loader dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-loader</artifactId>
<scope>provided</scope>
</dependency>
because of the need to extend the JarLauncher class.
Spring boot provides a special launcher that changes the java behaviour class loader. The class org.springframework.boot.loader.JarLauncher creates a special class loader and boostraps the application.
Since I wanted to launch the application as a window service, I chose Procrun as service manager.
Procrun needs two start and stop methods or one method with string array parameter (see procrun project for more details). Therefore I created a Bootsrap class that extended JarLauncher and implemented the methods that Procrun needs.
public class Bootstrap extends JarLauncher {
private static ClassLoader classLoader = null;
private static Bootstrap bootstrap = null;
protected void launch(String[] args, String mainClass, ClassLoader classLoader, boolean wait)
throws Exception {
// spring boot 1.2 Runnable runner = createMainMethodRunner(mainClass, args, classLoader);
// spring boot 1.2 Thread runnerThread = new Thread(runner);
Thread runnerThread = new Thread(() -> {
try {
createMainMethodRunner(mainClass, args, classLoader).run();
}
catch(Exception ex) {}
});
runnerThread.setContextClassLoader(classLoader);
runnerThread.setName(Thread.currentThread().getName());
runnerThread.start();
if (wait == true) {
runnerThread.join();
}
}
public static void start (String []args) {
bootstrap = new Bootstrap ();
try {
JarFile.registerUrlProtocolHandler();
classLoader = bootstrap.createClassLoader(bootstrap.getClassPathArchives());
bootstrap.launch(args, bootstrap.getMainClass(), classLoader, true);
}
catch (Exception ex) {
ex.printStackTrace();
System.exit(1);
}
}
public static void stop (String []args) {
try {
if (bootstrap != null) {
bootstrap.launch(args, bootstrap.getMainClass(), classLoader, true);
bootstrap = null;
classLoader = null;
}
}
catch (Exception ex) {
ex.printStackTrace();
System.exit(1);
}
}
public static void main(String[] args) {
String mode = args != null && args.length > 0 ? args[0] : null;
if ("start".equals(mode)) {
Bootstrap.start(args);
}
else if ("stop".equals(mode)) {
Bootstrap.stop(args);
}
}
}
In the spring boot application class I changed the main method with:
private static ApplicationContext applicationContext = null;
public static void main(String[] args) {
String mode = args != null && args.length > 0 ? args[0] : null;
if (logger.isDebugEnabled()) {
logger.debug("PID:" + ManagementFactory.getRuntimeMXBean().getName() +
" Application mode:" + mode + " context:" + applicationContext);
}
if (applicationContext != null && mode != null && "stop".equals(mode)) {
System.exit(SpringApplication.exit(applicationContext, new ExitCodeGenerator() {
@Override
public int getExitCode() {
return 0;
}
}));
}
else {
SpringApplication app = new SpringApplication(TestProcrunApplication.class);
applicationContext = app.run(args);
if (logger.isDebugEnabled()) {
logger.debug("PID:" + ManagementFactory.getRuntimeMXBean().getName() +
" Application started context:" + applicationContext);
}
}
}
Then, I installed the service with prunsrv.exe
prunsrv.exe //IS//test-procrun --DisplayName="test-procrun" --Description="test-procrun" --Startup=auto --Install=%CD%\prunsrv.exe --Jvm=auto --Classpath=%CD%..\target\test-procrun-0.0.1-SNAPSHOT.jar --StartMode=jvm --StartClass=it.test.procrun.Bootstrap --StartMethod=start --StartParams=start --StopMode=jvm --StopClass=it.test.procrun.Bootstrap --StopMethod=stop --StopParams=stop --StdOutput=auto --StdError=auto --LogPath=%CD% --LogLevel=Debug
source code spring boot 1.2,1.3
source code spring boot 1.4
Labels:
procrun,
spring boot,
windows service
Subscribe to:
Post Comments (Atom)
I have followed this example with my own app, but it never returns to service manager saying it is start, usually get a timeout error. I have increased the ServicesPipeTimeout. Any other suggestions?
ReplyDeleteBut if you run your application with java -jar your_app.jar it works?
DeleteCan you post commons-daemon.log?
yes, it will run that way and takes about 17-20 seconds to initialize.
Delete[2015-03-23 19:20:08] [info] ( prunsrv.c:1683) [ 2592] Commons Daemon procrun (1.0.15.0 32-bit) started
[2015-03-23 19:20:08] [info] ( prunsrv.c:725 ) [ 2592] Starting service 'AutoAPI-procrun' ...
[2015-03-23 19:21:08] [debug]
only this log...
DeleteIn my example I had
[2015-03-24 18:19:04] [debug] ( prunsrv.c:1679) [ 3116] Commons Daemon procrun log initialized
[2015-03-24 18:19:04] [info] ( prunsrv.c:1683) [ 3116] Commons Daemon procrun (1.0.15.0 32-bit) started
[2015-03-24 18:19:04] [info] ( prunsrv.c:1596) [ 3116] Running 'test-procrun' Service...
[2015-03-24 18:19:04] [debug] ( prunsrv.c:1374) [ 3940] Inside ServiceMain...
[2015-03-24 18:19:04] [debug] ( prunsrv.c:844 ) [ 3940] reportServiceStatusE: 2, 0, 3000, 0
[2015-03-24 18:19:04] [info] ( prunsrv.c:1127) [ 3940] Starting service...
[2015-03-24 18:19:04] [debug] ( javajni.c:233 ) [ 3940] loading jvm 'C:\Programmi\Java\jre7\bin\client\jvm.dll'
[2015-03-24 18:19:04] [debug] ( javajni.c:704 ) [ 3112] Jvm Option[0] -Djava.class.path=C:\prj\test-procrun\procrun\..\target\test-procrun-0.0.1-SNAPSHOT.jar
[2015-03-24 18:19:05] [debug] ( javajni.c:704 ) [ 3112] Jvm Option[1] exit
[2015-03-24 18:19:05] [debug] ( javajni.c:888 ) [ 3112] argv[0] = start
[2015-03-24 18:19:05] [debug] ( javajni.c:941 ) [ 3112] Java Worker thread started it/test/procrun/Bootstrap:start
[2015-03-24 18:19:06] [debug] ( prunsrv.c:1186) [ 3940] Java started it/test/procrun/Bootstrap
[2015-03-24 18:19:06] [info] ( prunsrv.c:1284) [ 3940] Service started in 1131 ms.
[2015-03-24 18:19:06] [debug] ( prunsrv.c:844 ) [ 3940] reportServiceStatusE: 4, 0, 0, 0
[2015-03-24 18:19:06] [debug] ( prunsrv.c:1528) [ 3940] Waiting for worker to finish...
[2015-03-24 18:20:10] [debug] ( javajni.c:964 ) [ 3112] Java Worker thread finished it/test/procrun/Bootstrap:start with status=0
[2015-03-24 18:20:10] [debug] ( prunsrv.c:1533) [ 3940] Worker finished.
[2015-03-24 18:20:10] [debug] ( prunsrv.c:1559) [ 3940] Waiting for all threads to exit
I added in the example a sleep for initialize it took 60sec and it works.
I believe that you have a environment problem. In my example into install.bat I add --StartMode=jvm --Jvm=auto this means that the procrun find the JVM from the Windows registry. (see http://commons.apache.org/proper/commons-daemon/procrun.html for more detail). Can you change --StartMode=jvm in --StartMode=java and add JAVA_HOME variable in your environment?
in the example I used procrun 32bit you need to jvm 32bit.
DeleteI get an error : Unable to find a single main class from the following candidates [org.test.Bootstrap, org.test.MyApplication]
ReplyDeletehow you start the application as service? if yes Can you post commons-daemon.log?
DeleteHello. Today classes has moved ot BOOT-INF directory in spring uber-jar, and procrun cannot find bootstrap ...
ReplyDeleteWell, spring-boot dont accepts two main classes, how do avoid this with your two, one in Bootstrap class and one in spring boot application class??
ReplyDeleteYour solution worked great for me up to Spring Boot version 1.3.
ReplyDeleteUnfortunately it something has changed in Spring Boot 1.4.0 and there is a compilation error now. Have you tried updating this for SB 1.4.0?
It is piece of very good code that saved my ass! Thanks!
This comment has been removed by the author.
DeleteI updated the git project (https://github.com/francesc79/test-procrun)
DeleteThanks. You are great!
DeleteYou are really saved my day, Buddy! Great article!
ReplyDeleteHi, thank you for the article and my service starts nicely.
ReplyDeleteI wonder how the stop works.
It does does go into Application (@SpringBootApplication) but where does the applicationContext comes from? It's initialised as null so it will try to start another instance of my SpringApplication and it fails since port is in use. How did you resolve that?
[2017-01-20 11:12:10] [error] ( javajni.c:863 ) [ 8280] FindClass it/test/procrun/Bootstrap failed
ReplyDelete[2017-01-20 11:12:10] [debug] ( javajni.c:964 ) [ 8280] Java Worker thread finished it/test/procrun/Bootstrap:start with status=3
[2017-01-20 11:12:10] [error] ( prunsrv.c:1183) [11564] Failed to start Java
[2017-01-20 11:12:10] [error] ( prunsrv.c:1536) [11564] ServiceStart returned 4
You can help me?
Check if inside your jar exist it/test/procrun/Bootstrap.class if not you have build problem please post maven log.
DeleteSame error for me and it exists in the jar and no build error
DeleteHello!
ReplyDeleteI have try the example but I get some errors. On install all right but on run failed.
> Install.bat log:
xxxxxxxxxxxxxxx
[2017-10-16 14:45:11] [debug] ( prunsrv.c:1679) [ 5736] Commons Daemon procrun log initialized
[2017-10-16 14:45:11] [info] ( prunsrv.c:1683) [ 5736] Commons Daemon procrun (1.0.15.0 64-bit) started
[2017-10-16 14:45:11] [debug] ( prunsrv.c:561 ) [ 5736] Installing service...
[2017-10-16 14:45:11] [info] ( prunsrv.c:600 ) [ 5736] Service test-procrun name test-procrun
[2017-10-16 14:45:11] [debug] ( prunsrv.c:616 ) [ 5736] Setting service description test-procrun
[2017-10-16 14:45:11] [info] ( prunsrv.c:634 ) [ 5736] Service 'test-procrun' installed
[2017-10-16 14:45:11] [info] ( prunsrv.c:1764) [ 5736] Commons Daemon procrun finished
xxxxxxxxxxxxxxx
> run.bat log:
[2017-10-16 14:48:12] [debug] ( prunsrv.c:1679) [ 6468] Commons Daemon procrun log initialized
[2017-10-16 14:48:12] [info] ( prunsrv.c:1683) [ 6468] Commons Daemon procrun (1.0.15.0 64-bit) started
[2017-10-16 14:48:12] [info] ( prunsrv.c:725 ) [ 6468] Starting service 'test-procrun' ...
[2017-10-16 14:48:13] [error] ( prunsrv.c:746 ) [ 6468] Failed to start 'test-procrun' service
[2017-10-16 14:48:13] [error] ( prunsrv.c:746 ) [ 6468] Access denied.
[2017-10-16 14:48:13] [info] ( prunsrv.c:754 ) [ 6468] Start service finished.
[2017-10-16 14:48:13] [error] ( prunsrv.c:1755) [ 6468] Commons Daemon procrun failed with exit value: 5 (Failed to start service)
[2017-10-16 14:48:13] [error] ( prunsrv.c:1755) [ 6468] Access denied.
I try the //TS// command "Run the service as a console application" and the application run, see log:
Delete[2017-10-16 14:59:39] [debug] ( prunsrv.c:1679) [ 3980] Commons Daemon procrun log initialized
[2017-10-16 14:59:39] [info] ( prunsrv.c:1683) [ 3980] Commons Daemon procrun (1.0.15.0 64-bit) started
[2017-10-16 14:59:39] [info] ( prunsrv.c:1580) [ 3980] Debugging 'test-procrun' service...
[2017-10-16 14:59:39] [debug] ( prunsrv.c:1374) [ 3980] Inside ServiceMain...
[2017-10-16 14:59:39] [debug] ( prunsrv.c:844 ) [ 3980] reportServiceStatusE: 2, 0, 3000, 0
[2017-10-16 14:59:39] [info] ( prunsrv.c:1127) [ 3980] Starting service...
[2017-10-16 14:59:39] [debug] ( javajni.c:222 ) [ 3980] Invalid RuntimeLib 'C:\Java\jre1.8.0_74\bin\client\jvm.dll'
[2017-10-16 14:59:39] [debug] ( javajni.c:224 ) [ 3980] Using Jre JavaHome 'C:\Java\jre1.8.0_74'
[2017-10-16 14:59:39] [debug] ( javajni.c:233 ) [ 3980] loading jvm 'C:\Java\jre1.8.0_74\bin\server\jvm.dll'
[2017-10-16 14:59:39] [debug] ( javajni.c:704 ) [ 5632] Jvm Option[0] -Djava.class.path=C:\tmp\master\test-procrun-0.0.2-SNAPSHOT.jar
[2017-10-16 14:59:39] [debug] ( javajni.c:704 ) [ 5632] Jvm Option[1] exit
[2017-10-16 14:59:39] [debug] ( javajni.c:888 ) [ 5632] argv[0] = start
[2017-10-16 14:59:39] [debug] ( javajni.c:941 ) [ 5632] Java Worker thread started it/test/procrun/Bootstrap:start
[2017-10-16 14:59:40] [debug] ( prunsrv.c:1186) [ 3980] Java started it/test/procrun/Bootstrap
[2017-10-16 14:59:40] [info] ( prunsrv.c:1284) [ 3980] Service started in 1112 ms.
[2017-10-16 14:59:40] [debug] ( prunsrv.c:844 ) [ 3980] reportServiceStatusE: 4, 0, 0, 0
[2017-10-16 14:59:40] [debug] ( prunsrv.c:1528) [ 3980] Waiting for worker to finish...
[2017-10-16 14:59:44] [debug] ( javajni.c:964 ) [ 5632] Java Worker thread finished it/test/procrun/Bootstrap:start with status=0
[2017-10-16 14:59:44] [debug] ( prunsrv.c:1533) [ 3980] Worker finished.
[2017-10-16 14:59:44] [debug] ( prunsrv.c:1559) [ 3980] Waiting for all threads to exit
[2017-10-16 14:48:13] [error] ( prunsrv.c:746 ) [ 6468] Access denied.
DeleteI think you have privileges problems. Check windows events log if you have more information for find the real problem.
Hi, I fixed setting the procrun path to folder local:
Deleteset PR_INSTALL%CD%
thank you
I tried but getting error during service start .
ReplyDeleteWindows could not start the MyService service on Local Computer.
Error 1067: The process terminated unexpectedly.
log:
[2017-10-27 15:59:07] [debug] ( prunsrv.c:1374) [ 9680] Inside ServiceMain...
[2017-10-27 15:59:07] [debug] ( prunsrv.c:844 ) [ 9680] reportServiceStatusE: 2, 0, 3000, 0
[2017-10-27 15:59:07] [info] ( prunsrv.c:1127) [ 9680] Starting service...
Please help
Can you try to uninstall reboot the pc and install the service again?
ReplyDeleteI tried but no luck
ReplyDeletein the install.bat tray to change --StartMode and --StopMode from jvm to Java. Define in your system JAVA_HOME environment variable for more details see https://commons.apache.org/proper/commons-daemon/procrun.html
ReplyDeleteBerita Terupdate SeIndonesia
ReplyDeleteBerita Keren