我遇到了类似的问题,但发现其他人(Francesco Zanutto)很亲切地写了一篇关于他们努力的博客文章。 他们的解决方案对我有用。我不相信他们为实现此代码所花费的时间。
http://zazos79.blogspot.com/2015/02/spring-boot-12-run-as-windows-service.html
与我在您的示例中看到的 exe 模式相比,他使用的是 jvm 启动和停止模式。有了这个,他能够扩展 Spring Boot 的 JarLauncher 来处理来自 Windows 服务的“启动”和“停止”命令,我相信你正在寻找优雅的关闭。
与他的示例一样,您将添加多个主要方法,具体取决于您的实现,您需要指出启动器现在应该调用哪些方法。我正在使用 Gradle,只需将以下内容添加到我的 build.gradle 中:
springBoot{
mainClass = 'mydomain.app.MyApplication'
}
我的 Procrun 安装脚本:
D:\app\prunsrv.exe //IS//MyServiceName ^
--DisplayName="MyServiceDisplayName" ^
--Description="A Java app" ^
--Startup=auto ^
--Install=%CD%\prunsrv.exe ^
--Jvm=%JAVA_HOME%\jre\bin\server\jvm.dll ^
--Classpath=%CD%\SpringBootApp-1.1.0-SNAPSHOT.jar; ^
--StartMode=jvm ^
--StartClass=mydomain.app.Bootstrap ^
--StartMethod=start ^
--StartParams=start ^
--StopMode=jvm ^
--StopClass=mydomain.app.Bootstrap ^
--StopMethod=stop ^
--StopParams=stop ^
--StdOutput=auto ^
--StdError=auto ^
--LogPath=%CD% ^
--LogLevel=Debug
JarLauncher 扩展类:
package mydomain.app;
import org.springframework.boot.loader.JarLauncher;
import org.springframework.boot.loader.jar.JarFile;
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 {
Runnable runner = createMainMethodRunner(mainClass, args, classLoader);
Thread runnerThread = new Thread(runner);
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);
}
}
}
我的主要 Spring 应用程序类:
package mydomain.app;
import java.lang.management.ManagementFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.ExitCodeGenerator;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan
@EnableAutoConfiguration
public class MyApplication {
private static final Logger logger = LoggerFactory.getLogger(MyApplication.class);
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(MyApplication.class);
applicationContext = app.run(args);
if (logger.isDebugEnabled()) {
logger.debug("PID:" + ManagementFactory.getRuntimeMXBean().getName() + " Application started context:" + applicationContext);
}
}
}
}