为什么要用 WinSW 来跑 JAR
做后端开发的人应该都遇到过这种情况:用 Spring Boot 写了一个 API 服务,本地开发环境一切正常,到了部署阶段发现服务器是 Windows Server。直接双击跑 java -jar,命令行窗口一关服务就没了。写个 bat 扔启动项里,用户登录了才启动,服务器重启还得手动登录。这种方案别说当生产环境用了,自己测试都觉得不靠谱。
把 Java 程序注册成 Windows 服务的好处很直接:开机自动启动、不需要用户登录、崩溃了可以自动重启、还能用 sc query 或者 services.msc 统一管理。实现方案有好几种,NSSM 算一个,微软自家的 sc.exe + srvany 也可以,但在实际对比之后,WinSW 在配置灵活性、社区活跃度和维护频率上是最省心的选择。
WinSW 是什么
WinSW 全称 Windows Service Wrapper,是一个开源工具,能把任何可执行程序包装成 Windows 服务来管理。项目托管在 GitHub 上(winsw/winsw),使用宽松的 MIT 许可证,可以随便用在商业项目里。
它的原理很简单:提供一个 exe 文件,配上同名的 XML 配置文件,exe 启动时读取 XML 里的参数,然后把你指定的程序(不管是 exe 还是 java -jar)作为一个子进程拉起来,同时向 Windows SCM(服务控制管理器)注册自己。这样一来,Windows 就当它是一个标准服务来对待了。
WinSW 目前主要提供两种版本:依赖 .NET Framework 4.6.1+ 的版本,以及基于 .NET 6/7/8 的原生 exe(不需要额外装运行时)。Windows 10 1511 以上版本系统自带 .NET,直接用 .NET 版本的最省事。
准备工作
先说你需要准备的东西:
- 一个打包好的 JAR 文件,比如 app.jar
- 服务器上装好的 JDK 或 JRE,确认 java 命令能在命令行正常执行
- WinSW 的 exe 文件,从 GitHub Releases 页面下载最新版
下载 WinSW 的时候注意选对版本。如果你的服务器是 64 位 Windows,下载 WinSW-x64.exe;如果是 32 位,下载 WinSW-x86.exe。也有不分架构的 .NET 版本,叫 WinSW-net461.exe,只要系统装了 .NET 4.6.1 以上就能跑。
具体操作步骤
第一步:重命名 WinSW 文件
把下载的 WinSW-x64.exe 重命名为你想注册的服务名,比如 myapp.exe。这个 exe 的文件名就是后面注册到 Windows 里的服务名,所以取一个清晰好认的名字。
第二步:编写 XML 配置文件
在同一个目录下创建一个同名的 XML 文件,myapp.xml。下面是一个生产可用的模板:
<service>
<id>myapp</id>
<name>MyApp Service</name>
<description>我的 Java 后端服务</description>
<executable>java</executable>
<arguments>-jar D:\services\myapp\app.jar --server.port=8080</arguments>
<logmode>rotate</logmode>
<logpath>D:\services\myapp\logs</logpath>
<onfailure>restart</onfailure>
<resetfailure>1</resetfailure>
<stoptimeout>15</stoptimeout>
<startmode>Automatic</startmode>
<env name="JAVA_HOME" value="C:\Program Files\Java\jdk-17"/>
<env name="PATH" value="%JAVA_HOME%\bin;%PATH%"/>
</service>
几个关键字段说明:
- id:服务唯一标识,和 exe 文件名保持一致
- executable + arguments:就是你要运行的命令,把 java -jar 拆开写
- logmode:建议用 rotate,按文件大小滚动日志,不会撑爆磁盘
- onfailure:进程崩溃后自动重启,生产环境必备
- startmode:设为 Automatic 就是开机自启
- stoptimeout:给程序留足时间优雅关闭
第三步:安装服务
以管理员身份打开 PowerShell 或 CMD,进入 exe 所在目录,执行:
myapp.exe install
看到输出 Successfully installed 就说明注册成功了。这时打开 services.msc 应该能看到 MyApp Service 已经在列表里,启动类型为自动。
第四步:启动服务
myapp.exe start
也可以用 Windows 标准方式:
net start myapp
检查服务状态:
myapp.exe status
开机自启的验证方法
很多人配置完以为就完事了,结果重启服务器发现服务没跑起来。问题通常出在几个地方:
- JAVA_HOME 环境变量没正确设置,XML 里用 <env> 显式指定 JDK 路径是最稳的做法
- JAR 文件的路径用的是相对路径,服务的工作目录和手动执行不一样,统一用绝对路径
- 端口被占用,服务启动就退出了,日志里能看到原因
验证方法很简单:重启服务器,等系统完全启动后,执行 sc query myapp,看看 STATE 是不是 RUNNING。或者直接调一下你的 API 接口确认服务正常运行。
常用管理命令
WinSW 提供了完整的生命周期管理命令,都不需要装额外工具:
myapp.exe install # 安装服务
myapp.exe uninstall # 卸载服务
myapp.exe start # 启动服务
myapp.exe stop # 停止服务
myapp.exe restart # 重启服务
myapp.exe status # 查看服务状态
容易踩的坑
说几个实际部署中容易出问题的地方:
中文路径。WinSW 对非 ASCII 字符的处理不太稳定,JAR 包路径、日志路径都建议用纯英文,不要包含中文或特殊符号。
日志权限。WinSW 默认以 SYSTEM 账户运行服务,如果日志目录没有 SYSTEM 的写入权限,服务启动会静默失败。提前给目录加好权限,或者把日志目录放到服务账号有权限的位置。
进程残留。某些 Java 程序在收到 SIGTERM 后不会立即退出,WinSW 默认等 15 秒,超时后强行杀进程。如果你的程序需要更长的关闭时间,调整 stoptimeout 值。
JVM 参数。如果有 -Xmx、-Xms 等 JVM 参数,全部写在 arguments 里,放在 -jar 之前:
<arguments>-Xmx512m -Xms256m -jar D:\services\myapp\app.jar</arguments>
总结
用 WinSW 把 JAR 注册成 Windows 服务,本质上就是三步:下载 exe、写配置文件、跑 install 命令。配置对了之后,服务器断电重启、计划维护重启,服务都会自动跟上,不再需要人工介入。相比 NSSM 需要图形界面操作、sc.exe 配置太原始的问题,WinSW 用一份 XML 就能搞定全部配置,还能写进自动化脚本里,是 Windows 服务场景下性价比较高的方案。