Skip to content

Spring Boot 应用的系统服务安装指南 🚀

概述

在实际的生产环境中,我们不能总是手动使用 java -jar 命令来启动 Spring Boot 应用。想象一下,如果服务器重启了,难道要手动登录服务器重新启动应用吗?这显然不现实!

IMPORTANT

Spring Boot 应用可以作为系统服务安装,实现开机自启动、自动重启等企业级特性,这是生产环境部署的标准做法。

本文将深入探讨如何将 Spring Boot 应用安装为不同类型的系统服务,包括现代的 systemd 服务、传统的 init.d 服务,以及 Windows 服务。

为什么需要系统服务? 🤔

传统方式的痛点

bash
# 手动启动应用
java -jar myapp.jar

# 问题:
# 1. 服务器重启后需要手动重启应用
# 2. 应用崩溃后无法自动恢复
# 3. 难以统一管理多个应用
# 4. 缺乏标准化的启停控制
bash
# 作为系统服务启动
systemctl start myapp
systemctl enable myapp  # 开机自启

# 优势:
# 1. 开机自动启动
# 2. 崩溃自动重启
# 3. 统一的服务管理
# 4. 标准化的日志管理

系统服务的核心价值

systemd 服务安装 (推荐) ⭐

什么是 systemd?

NOTE

systemd 是现代 Linux 发行版的标准初始化系统,已经取代了传统的 System V init。它提供了更强大的服务管理功能和更好的依赖管理。

创建 systemd 服务

假设我们有一个名为 user-service 的 Spring Boot 应用:

kotlin
@SpringBootApplication
class UserServiceApplication

fun main(args: Array<String>) {
    runApplication<UserServiceApplication>(*args)
}
bash
# 1. 创建应用目录
sudo mkdir -p /var/myapp

# 2. 复制 JAR 文件
sudo cp user-service-1.0.0.jar /var/myapp/myapp.jar

# 3. 创建专用用户
sudo useradd --system --shell /usr/sbin/nologin myapp
sudo chown -R myapp:myapp /var/myapp

配置 systemd 服务文件

创建服务配置文件 /etc/systemd/system/myapp.service

ini
[Unit]
Description=My Spring Boot Application  
After=syslog.target network.target      

[Service]
User=myapp                              
Group=myapp                             

Type=exec                               
ExecStart=/usr/bin/java -jar /var/myapp/myapp.jar  
WorkingDirectory=/var/myapp             
SuccessExitStatus=143                   

# 重启策略
Restart=always                          
RestartSec=10                          

# 环境变量
Environment=SPRING_PROFILES_ACTIVE=prod 
Environment=JAVA_OPTS=-Xmx512m         

[Install]
WantedBy=multi-user.target             

TIP

  • After 指定服务启动顺序,确保网络和日志系统先启动
  • SuccessExitStatus=143 是 Spring Boot 优雅关闭的退出码
  • Restart=always 确保应用崩溃后自动重启

启动和管理服务

bash
# 重新加载 systemd 配置
sudo systemctl daemon-reload

# 启动服务
sudo systemctl start myapp

# 设置开机自启
sudo systemctl enable myapp

# 查看服务状态
sudo systemctl status myapp

# 查看日志
sudo journalctl -u myapp -f

实际业务场景示例

电商订单服务的 systemd 配置
ini
[Unit]
Description=E-commerce Order Service
After=syslog.target network.target mysql.service redis.service

[Service]
User=orderapp
Group=orderapp

Type=exec
ExecStart=/usr/bin/java -jar /var/orderservice/order-service.jar
WorkingDirectory=/var/orderservice

# 健康检查
ExecStartPost=/bin/sleep 30
ExecStartPost=/usr/bin/curl -f http://localhost:8080/actuator/health

# 重启策略
Restart=always
RestartSec=15
StartLimitInterval=300
StartLimitBurst=5

# 环境配置
Environment=SPRING_PROFILES_ACTIVE=prod
Environment=JAVA_OPTS=-Xmx2g -XX:+UseG1GC
Environment=DATABASE_URL=jdbc:mysql://localhost:3306/orders
Environment=REDIS_URL=redis://localhost:6379

# 资源限制
LimitNOFILE=65536
LimitNPROC=4096

[Install]
WantedBy=multi-user.target

init.d 服务安装 (传统方式)

创建可执行 JAR

首先需要配置构建工具生成"完全可执行"的 JAR:

xml
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <executable>true</executable>  
    </configuration>
</plugin>
kotlin
tasks.named<BootJar>("bootJar") {
    launchScript()  
}

WARNING

完全可执行的 JAR 在文件前嵌入了启动脚本,某些工具(如 jar -xf)可能无法正确处理这种格式。

安装为 init.d 服务

bash
# 1. 复制 JAR 到目标目录
sudo cp myapp.jar /var/myapp/

# 2. 创建符号链接到 init.d
sudo ln -s /var/myapp/myapp.jar /etc/init.d/myapp

# 3. 设置执行权限
sudo chmod +x /etc/init.d/myapp

# 4. 启动服务
sudo service myapp start

# 5. 设置开机自启
sudo update-rc.d myapp defaults

init.d 服务的特性

服务安全配置 🔒

用户权限管理

CAUTION

永远不要以 root 用户运行 Spring Boot 应用!这是严重的安全隐患。

bash
# 创建专用用户(无登录权限)
sudo useradd --system --shell /usr/sbin/nologin --home /var/myapp myapp

# 设置文件所有者
sudo chown myapp:myapp /var/myapp/myapp.jar

# 设置文件权限(只读和执行)
sudo chmod 500 /var/myapp/myapp.jar

# 防止文件被修改(即使是 root)
sudo chattr +i /var/myapp/myapp.jar

配置文件安全

对于 init.d 服务的配置文件:

bash
# 设置配置文件权限
sudo chmod 400 /var/myapp/myapp.conf
sudo chown root:root /var/myapp/myapp.conf
myapp.conf 配置示例
properties
# JVM 配置
JAVA_OPTS=-Xmx1024M -XX:+UseG1GC

# 日志配置
LOG_FOLDER=/var/log/myapp
LOG_FILENAME=myapp.log

# 运行用户
RUN_AS_USER=myapp

# 应用参数
RUN_ARGS=--spring.profiles.active=prod

服务配置定制

构建时定制

在构建 JAR 时可以定制启动脚本的属性:

xml
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <executable>true</executable>
        <embeddedLaunchScriptProperties>
            <mode>service</mode>
            <initInfoDescription>My Spring Boot Service</initInfoDescription>
            <initInfoShortDescription>MyApp Service</initInfoShortDescription>
            <logFolder>/var/log/myapp</logFolder>
            <pidFolder>/var/run/myapp</pidFolder>
        </embeddedLaunchScriptProperties>
    </configuration>
</plugin>
kotlin
tasks.named<BootJar>("bootJar") {
    launchScript {
        properties(mapOf(
            "mode" to "service",
            "initInfoDescription" to "My Spring Boot Service",
            "logFolder" to "/var/log/myapp",
            "pidFolder" to "/var/run/myapp"
        ))
    }
}

运行时环境变量

变量名描述默认值
MODE运行模式auto
RUN_AS_USER运行用户JAR 文件所有者
JAVA_HOMEJava 安装路径从 PATH 自动发现
JAVA_OPTSJVM 参数
RUN_ARGS应用参数
LOG_FOLDER日志目录/var/log
PID_FOLDERPID 文件目录/var/run

Windows 服务

对于 Windows 环境,可以使用 winsw 工具将 Spring Boot 应用安装为 Windows 服务:

NOTE

Windows 服务的配置相对复杂,通常需要第三方工具如 winswNSSM 来实现。

最佳实践总结 ✅

选择建议

部署检查清单

生产环境部署检查

  • [ ] 创建专用的非特权用户
  • [ ] 设置正确的文件权限
  • [ ] 配置适当的 JVM 参数
  • [ ] 设置环境特定的配置文件
  • [ ] 配置日志轮转
  • [ ] 设置监控和告警
  • [ ] 测试服务的启动、停止和重启
  • [ ] 验证开机自启功能

常见问题排查

服务启动失败

检查 /var/log/<appname>.log 或使用 journalctl -u <service-name> 查看详细错误信息。

权限问题

确保服务用户对应用目录和日志目录有适当的读写权限。

通过将 Spring Boot 应用安装为系统服务,我们实现了企业级的应用部署和管理,为生产环境的稳定运行奠定了坚实基础! 🎉