前言

在前一篇文章中,我们讨论了如何将项目打包成EXE文件并绑定JDK运行时。然而,这种方式存在一个明显缺陷:运行时会启动控制台窗口,一旦误操作该窗口,可能导致程序异常。

本文将介绍一种更优雅的解决方案:使用 将应用注册为系统服务,实现真正的后台运行。作为软件基金会的重要项目, 被广泛应用于企业级软件中,最典型的例子就是服务器,它正是使用 中的组件来实现系统服务化的。

资源下载

为方便读者实践,我已将完整代码和相关资源整理好,可通过以下链接直接获取:

项目资料:

一、 下载

到 官网下载时需要注意一个关键问题:官网提供的是--1.3.4开发包,而我们实际需要的是系统下的本地二进制包,例如:--1.3.4-bin-.zip。

这些二进制包在官网主页不易找到,这里提供直接下载地址:点击我跳转

我们选择最新版本:--1.3.4-bin-.zip,下载后内容如下:

在这里插入图片描述

特别注意:标准目录下的.exe是32位系统版本,如果您使用64位系统,请使用amd64目录下的.exe。

二、项目改造与服务制作

使用 制作系统服务需要可执行的JAR包而非EXE文件。此外,默认启动类org..boot..修改了加载规则,会导致 加载时出现类查找失败的问题。

首先,我们需要对项目结构进行适当调整,调整后的结构如下:

在这里插入图片描述

然后修改pom.xml配置:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <mainClass>org.example.testmvnpkgexespringboot.TestMvnPkgExeSpringbootApplication</mainClass>
        <excludes>
            <exclude>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </exclude>
        </excludes>
    </configuration>
</plugin>

因为需要使用JAR包并将 文件一起打包,我们需要修改打包规则:

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">

    <id>package</id>
    <formats>
        <format>zip</format>
    </formats>
    <includeBaseDirectory>true</includeBaseDirectory>
    <fileSets>
        <fileSet>
            <directory>runtime</directory>
            <outputDirectory>runtime</outputDirectory>
        </fileSet>
        <fileSet>
            <directory>conf</directory>
            <outputDirectory></outputDirectory>
            <includes>
                <include>*.properties</include>
            </includes>
        </fileSet>
        <fileSet>
            <directory>bat</directory>
            <outputDirectory></outputDirectory>
            <includes>
                <include>*.bat</include>
            </includes>
        </fileSet>
        <fileSet>
            <directory>daemon</directory>
            <outputDirectory></outputDirectory>
            <includes>
                <include>*.exe</include>
            </includes>
        </fileSet>
        <fileSet>
            <directory>${project.build.directory}</directory>
            <outputDirectory></outputDirectory>
            <includes>
                <include>pkg-sb.jar</include>
            </includes>
        </fileSet>
    </fileSets>
</assembly>

执行打包命令:

mvn clean -DskipTests package

生成的ZIP包解压后结构如下:

在这里插入图片描述

其中包含两个关键BAT脚本,分别用于安装和卸载服务:

服务安装脚本.bat:

@echo off
set SERVICE_EN_NAME=PkgSb
set SERVICE_CH_NAME=Package SB
set SERVICE_CH_DESC=Package SB
set BASEDIR=%CD%
set JAVA_HOME=%BASEDIR%runtime
set DATA_DIR=%BASEDIR%data
set CONFIG_FILE=%BASEDIR%config.properties
set CLASSPATH=%BASEDIR%pkg-sb.jar
set MAIN_CLASS=org.springframework.boot.loader.JarLauncher
set START_PARAM=
set STOP_CLASS=org.springframework.boot.loader.JarLauncher

set SRV=%BASEDIR%prunsrv.exe

set LOGPATH=%BASEDIR%logs

echo SERVICE_NAME: %SERVICE_EN_NAME%
echo JAVA_HOME: %JAVA_HOME%
echo MAIN_CLASS: %MAIN_CLASS%
echo prunsrv path: %SRV%

if"%JVM%" == "" goto findJvm
if exist "%JVM%" goto foundJvm
:findJvm
set"JVM=%JAVA_HOME%binserverjvm.dll"
if exist "%JVM%" goto foundJvm
echo can not find jvm.dll automatically,
echo please use COMMAND to localation it
echothen install service
goto end
:foundJvm
echo install service...
"%SRV%" //IS//%SERVICE_EN_NAME% ^
        --DisplayName="%SERVICE_CH_NAME%" ^
        --Description="%SERVICE_CH_DESC%" ^
        --Install="%SRV%" ^
        --Classpath="%CLASSPATH%" ^
        --JavaHome="%JAVA_HOME%" ^
        --Jvm="%JVM%" ^
        --JvmMs=256 ^
        --JvmMx=512 ^
        --Startup=auto ^
        ++JvmOptions=-Dfile.encoding=utf-8 ^
        ++JvmOptions=-Dvar1=var1-value-001 ^
        ++JvmOptions=-Dconfig.file=%CONFIG_FILE% ^
        ++JvmOptions=-Ddata.dir=%DATA_DIR% ^
        --StartMode=jvm ^
        --StartClass=%MAIN_CLASS% ^
        --StartMethod=main ^
        ++StartParams="%START_PARAM%" ^
        --StopMode=jvm ^
        --StopClass=%STOP_CLASS% ^
        --StopMethod=main ^
        --StopParams=stop^
        --LogPath=%LOGPATH% ^
        --StdOutput=auto ^
        --StdError=auto ^
        --PidFile=%LOGPATH%pid
echo install service successfully
pause

服务卸载脚本.bat:

@echo off
set BASEDIR=%CD%
echo %BASEDIR%
set SERVICE_NAME=PkgSb
set SRV=%BASEDIR%prunsrv.exe
echo uninstall service...
"%SRV%" //DS//%SERVICE_NAME%
echo uninstall service successfully
pause

三、运行与服务测试

完成上述步骤后,将打包好的ZIP文件拷贝到系统并解压,双击.bat脚本:

在这里插入图片描述

服务安装成功后,在系统服务管理器中可以看到我们创建的服务:

在这里插入图片描述

右键点击启动服务:

在这里插入图片描述

服务成功启动,并已配置为开机自启动。通过浏览器测试服务功能:

在这里插入图片描述

结果显示系统变量已正确传递plugin.exe应用程序错误,与前一节测试结果一致。

最后plugin.exe应用程序错误,测试服务卸载功能,执行.bat:

在这里插入图片描述

检查系统服务列表,确认服务已成功卸载。

技术要点与注意事项

1.服务停止机制: 对服务停止有严格要求,主要通过和两个参数控制。如果配置的停止方法无法正常执行,卸载服务会失败,只能通过手动终止进程后再卸载。

2.启动类兼容性:默认使用org..boot..作为启动类,它改写了加载规则。在本例中,我们采用了同一个方法处理启动和停止,通过参数区分不同操作:

public static void main(String[] args) {
    if(args!=null && args.length>0 && args[0].equals("stop")){
        System.exit(0);
        return;
    }
    SpringApplication.run(TestMvnPkgExeSpringbootApplication.class, args);
}

3.日志位置: 运行日志保存在应用目录下的logs文件夹中,可通过查看这些日志文件进行问题排查。

4.常见错误:如遇到[error] [13308] %1 不是有效的 Win32 应用程序错误,原因通常是.exe文件版本与系统不匹配,64位系统需使用amd64目录下的文件。

5.选型建议: 是一个成熟但配置较复杂的方案,虽然细节繁多,但作为基金会项目,其可靠性有充分保障。在下一篇文章中,我将介绍一个更加简便的服务制作工具。


限时特惠:
本站持续每日更新海量各大内部创业课程,一年会员仅需要98元,全站资源免费下载
点击查看详情

站长微信:Jiucxh

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注