目前正在做的一个项目,在客户的提供的服务器上Windows server服务器上运行一个spring boot项目,简单写了一个java -jar xxx.jar的启动脚本,之前一直运行正常,也没啥问题,但是最近突然无故自动停止,检查项目日志和系统日志也为发现具体问题,最后直接用一个简单办法解决:将这个服务做成系统服务运行。另外整理一下以前在Linux系统上将spring boot项目做成服务的过程。
Windows下jar包制作成服务
下载工具(WinSW)
下载地址: Github:winsw 发行版或者Gitee:winsw 发行版
选择其中两个文件下载即可:
1.WinSW-x64.exe
2.sample-minimal.xml
修改xml文件
修改下载下来的xml文件,主要内容如下(注意:出特殊标注处及注释内容外,其他地方不识别中文)
<service>
<!-- 服务ID,在windows系统中必须唯一的系统标识-->
<id>testApp</id>
<!-- 服务显示名称,不能使用中文,仅限英文、数字、横线等 -->
<name>test service</name>
<!-- 服务描述,描述服务的作用-这里是唯一可以有中文的 -->
<description>This service is a service created from a minimal configuration</description>
<!-- 设置环境变量 -->
<env name="JAVA_HOME" value="%JAVA_HOME%"/>
<!-- 启动可执行文件的路径,如果配置了Java环境变量,可以直接使用java替代。否则`使用全路径`(这里容易坑) -->
<executable>java</executable>
<!-- 传递给可执行文件的参数 -->
<arguments>-jar "C:\test\test.jar"</arguments>
<!-- 指定Windows服务的启动模式,它可以是下列值之一:开机、系统、自动或手动, 默认值是“Automatic” -->
<startmode>Automatic</startmode>
<!-- 配置日志路径 -->
<logpath>H:\testautostart\logs</logpath>
<!-- 日志输出模式,默认为append -->
<logmode>rotate</logmode>
</service>
其中日志输出模式有以下几种:
- append (追加模式)其特点是将日志文件全部输出在一个文件中,这个文件可能会越来越大
- rotate(旋转模式,推荐)当日志文件大小达到10兆(默认值),winsw会将日志重新输出到另外一份日志文件,默认最多保留8个
- reset(重置模式)每次重启服务都会重置日志文件
- none(忽略模式)几乎不会生成日志文件
文件配置
修改WinSW和sample-minimal.xml名称
将下载的文件与jar文件放置在一起,两个文件名修改为服务名(服务名自定义)
服务管理
注册服务
当前目录输入cmd,进入命令行模式,执行服务注册命令
testApp.exe install
执行完上述命令后,在服务中即可看见该服务。
卸载服务
当前目录输入cmd,进入命令行模式,执行服务注册命令
testApp.exe uninstall
其他服务命令
testApp.exe start:启动服务
testApp.exe stop:停⽌服务
testApp.exe restart:重启服务
testApp.exe status:输出当前服务的状态
Linux下将jar包制作成服务
准备JAR程序:
确保你的JAR程序是可执行的,并且已经放置在Linux系统中的某个目录下。
创建systemd服务文件:
- 进入/etc/systemd/system目录。
- 创建一个新的服务文件,例如myjarapp.service,其中myjarapp是你的服务名称。
编辑服务文件:
在服务文件中添加以下内容,根据你的实际情况进行修改:
[Unit]
Description=My JAR Application Service
After=syslog.target
[Service]
Type=simple
ExecStart=/usr/bin/java -jar /path/to/your/application.jar
WorkingDirectory=/path/to/your/application
User=yourusername
Group=yourgroupname
Restart=on-failure
[Install]
WantedBy=multi-user.target
- ExecStart:指定启动JAR程序的命令。
- WorkingDirectory:指定JAR程序的工作目录(可选)。
- User和Group:指定运行JAR程序的用户和组(可选)。
- Restart=on-failure:如果服务失败,则自动重启。
重新加载systemd配置:
运行sudo systemctl daemon-reload命令,以重新加载systemd的配置。
启动和管理服务:
- 启动服务:sudo systemctl start myjarapp.service
- 停止服务:sudo systemctl stop myjarapp.service
- 检查服务状态:sudo systemctl status myjarapp.service
- 查看服务日志:journalctl -u myjarapp.service
设置开机自启动:
- 启用开机自启动:sudo systemctl enable myjarapp.service
- 检查开机自启动状态:sudo systemctl list-unit-files | grep myjarapp.service
写在最后
在systemd的服务文件中的[Service]节中,可以看到有ExecStart命令,但是却没有STOP命令。但这不影响systemd停止服务。 systemd通过发送特定的信号给服务进程来请求它停止。这通常是通过向进程发送SIGTERM(终止信号)来实现的,如果进程没有在规定的时间内响应,systemd可能会发送SIGKILL(强制终止信号)来强制停止它。
在[Service]部分中,ExecStart命令用于启动服务,而停止服务的逻辑是由systemd内部处理的,基于服务的类型和运行状态。当你运行sudo systemctl stop myjarapp.service命令时,systemd会负责找到服务的进程ID(PID),并发送适当的信号来请求它停止。
对于Java应用程序(特别是那些作为JAR文件运行的),当接收到SIGTERM信号时,它们通常不会立即退出,因为Java虚拟机(JVM)默认不会立即响应这个信号。因此,你可能需要在你的Java应用程序中添加一些代码来监听这个信号,并优雅地关闭应用程序(例如,通过关闭数据库连接、释放资源、停止线程等)。这通常可以通过在Java应用程序中使用信号处理库或框架来实现,或者通过注册一个关闭钩子(shutdown hook)来响应JVM的关闭事件。然而,如果你的Java应用程序没有处理SIGTERM信号的逻辑,那么systemd在发送SIGTERM后等待一段时间(这个时间可以通过TimeoutStopSec选项在服务文件中配置)后,将会发送SIGKILL信号来强制终止进程。
总之,尽管在systemd的服务文件中没有Stop命令,但systemd仍然能够停止服务,这是通过发送适当的信号给服务进程来实现的。对于Java应用程序,你可能需要在代码中添加一些逻辑来优雅地处理这些信号。