使用Apache的Procrun将Springboot项目注册为windows服务(commons-daemon Procrun)

Java程序注册Windows服务、Springboot项目注册windows服务的几种方式

三种方法:

1、利用JAVA Service Wrapper
缺点:官方分专业版、标准版和社区版,64位没有社区版,非社区版收费;

2、使用WinSW,
地址:http://repo.jenkins-ci.org/releases/com/sun/winsw/winsw/
缺点:需要.Net运行环境支持
优点:网上资料很多,简单,稳定可靠;

3、使用Apache的Procrun(重点解决windows服务不能正常停止问题
地址:http://commons.apache.org/proper/commons-daemon/procrun.html
优点:tomcat使用的就是这个,稳定可靠,网上资料也不少,不依赖任何环境,有任务栏通知图标

本文重点介绍第三种方案

Apache的Procrun

在这里插入图片描述依据JDK版本使用不同的服务程序,根目录的服务程序时32位的
管理UI程序需要改名,名字和windows服务相同,必须是英文ID

在这里插入图片描述目录结构图
我的服务ID是vpm-gather_x64,上面的都比较简单,主要是脚本怎么写,直接上脚本:

编写安装脚本:运行时必须使用管理员权限

@echo off
cd /d "%~dp0"
rem 设置服务ID,使用当前目录名
for /f "delims=" %%i in ("%cd%") do set SERVICE_ID=%%~ni
echo SERVICE_ID: %SERVICE_ID%

rem 设置程序名称
set SERVICE_NAME=管理服务(服务中文名)
set SERVICE_DESC=服务中文描述。

rem 设置程序依赖及程序入口类
set BASE_HOME=%CD%
echo BASE_HOME: %BASE_HOME%

rem 自动识别jar包,本目录只能存在一个jar包
for /f "delims=" %%i in ('dir /b *.jar') do set JAR_FILE=%%i
set CLASSPATH=%BASE_HOME%\%JAR_FILE%
echo JAR_FILE: %CLASSPATH%

set MAIN_CLASS=org.springframework.boot.loader.JarLauncher
rem 设置prunsrv路径
set SRV=%BASE_HOME%\prunsrv.exe
echo SRV: %SRV%

rem 设置日志路径及日志文件前缀
set LOGPATH=%BASE_HOME%\logs

rem 设置jvm
if "%JVM%" == "" goto findJvm
if exist "%JVM%" goto foundJvm
:findJvm
set "JVM=%BASE_HOME%\jre\bin\server\jvm.dll"
echo JVM: %JVM%
if exist "%JVM%" goto foundJvm
echo 没有找到JVM,请确认安装包是否完整。
goto end
:foundJvm
echo 安装服务...
"%SRV%" //IS//%SERVICE_ID% --DisplayName="%SERVICE_NAME%" --Description="%SERVICE_DESC%" "--Classpath=%CLASSPATH%" "--Install=%SRV%" "--JavaHome=%BASE_HOME%" "--Jvm=%JVM%" --JvmMs=256 --JvmMx=1024 --Startup=auto --JvmOptions=-Djcifs.smb.client.dfs.disabled=false ++JvmOptions=-Djcifs.resolveOrder=DNS;-Dlogging.path="%BASE_HOME%\logs" --StartMode=jvm --StartClass=%MAIN_CLASS% --StartMethod=main --StopMode=jvm --StopClass=%MAIN_CLASS% --StopMethod=main --StopTimeout=30 --StopParams=stop --LogPath=%LOGPATH% --StdOutput=auto --StdError=auto

echo 安装完成,创建服务管理器 SERVICE_ID: %SERVICE_ID% ...
set MGR=%BASE_HOME%\%SERVICE_ID%.exe
rem 创建任务栏图标启动文件,适用Windows10,其它操作系统按实际情况修改
echo %MGR% //MS//%SERVICE_ID%  > "%SYSTEMDRIVE%\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp\%SERVICE_ID%.bat"
rem 显示任务栏图标并启动服务
echo 任务栏出现图标后,请主动关闭此窗口!!!
"%MGR%" //MR//%SERVICE_ID%
:end
pause

卸载脚本:运行时必须使用管理员权限

@echo off
cd /d "%~dp0"
for /f "delims=" %%i in ("%cd%") do set SERVICE_ID=%%~ni
set basedir=%CD%

echo 卸载服务管理器 SERVICE_ID: %SERVICE_ID% ...
"%BASEDIR%\%SERVICE_ID%.exe" //MQ//%SERVICE_ID%
del "%SYSTEMDRIVE%\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp\%SERVICE_ID%.bat"

echo 正在卸载服务 SERVICE_ID: %SERVICE_ID% ...
"%BASEDIR%\prunsrv.exe" //DS//%SERVICE_ID%
echo 服务卸载完毕。
pause

解决Springboot项目服务关闭失败问题:

Procrun关闭服务需要调用一个类的一个方法,项目结构同mian函数,类在项目中调用不了,必须在springboot loader中,否则服务关闭不了,本人没有找到springboot项目的boot loader关闭方式,方法如下:
1、注意脚本种注册服务参数:重点参数:–StopParams=stop,后续springboot主类种需要用到这个“stop”

2、Springboot项目启动类
注意:Procrun调用主类启动和调用主类关闭时参数不一样,通过参数判断是否时关闭,同时Procrun调用虚拟机的特殊性,classloader不相同,不采用特殊写法会找不到启动时的ApplicationContext 。

package com.sailen.vpm.gather;

import java.util.concurrent.Callable;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.ApplicationContext;


@SpringBootApplication(scanBasePackages = {"com.sailen.vpm.gather"})
public class VpmGatherApplication extends SpringBootServletInitializer {
	
	private transient static final Logger LOGGER = LogManager.getLogger();
	
	private static final String BIND_STOP_CALLBACK = VpmGatherApplication.class.getName() + "#APP_STOP_CALLBACK";
	
	private static ApplicationContext CONTEXT;
	
	public static void main(String[] args) throws Exception {
		if (args != null && args.length > 0 && args[0].equals("stop")) {
			// 获取关闭回调对象
			Callable<?> callback = (Callable<?>) System.getProperties().get(BIND_STOP_CALLBACK);
			if (callback != null) {
				callback.call();
			} else {
				LOGGER.error("系统可能未启动,关闭callback不存在,无法执行关闭操作。");
			}
		} else {
			LOGGER.info("系统开始启动......");
			CONTEXT = SpringApplication.run(VpmGatherApplication.class, args);
			
			// 注册关闭回调对象
			Callable<?> callback = () -> stop();
			System.getProperties().put(BIND_STOP_CALLBACK, callback);
		}
	}

	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
		return application.sources(VpmGatherApplication.class);
	}
	
	private static Object stop() {
		if (CONTEXT != null) {
			LOGGER.info("系统开始关闭......");
			int exitCode = SpringApplication.exit(CONTEXT, () -> 0);
			LOGGER.info("系统开始关闭结果:{}", exitCode);
			System.exit(exitCode);
		} else {
			LOGGER.error("系统运行环境不存在,无法执行关闭操作。");
		}
		return null;
	}
}


做完就可以试试了
在这里插入图片描述

在这里插入图片描述

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值