必须用绝对路径写execstart(如/usr/bin/java -jar /path/app.jar),并显式指定user、workingdirectory、restart策略,再执行daemon-reload、enable、start才能实现java应用开机自启。

OpenJDK 本身不是服务,不能直接用 systemd 启动;真正要配置开机自启的是你用 OpenJDK 运行的 Java 应用(如 app.jar)。关键不在 JDK 装在哪,而在 .service 文件里是否正确调用了 java 命令并指向了你的程序。
怎么写 ExecStart 才不会找不到 java 命令
系统启动时 $PATH 极其精简,java 命令大概率不可见。硬写 java -jar app.jar 必然失败。
- 必须用绝对路径:查清楚你的
java在哪,常用位置有/usr/bin/java(系统包管理安装)、/opt/jdk-17.0.1/bin/java(手动解压版) - 运行前先手动验证:
sudo -u myappuser /usr/bin/java -version和sudo -u myappuser /usr/bin/java -jar /opt/myapp/app.jar都得成功 - 如果用了非系统自带 JDK(比如 Temurin 或 Corretto),
ExecStart中必须显式写全路径,不能依赖JAVA_HOME环境变量——systemd默认不读 shell 的.bashrc或/etc/profile
User 和 WorkingDirectory 设错会导致权限或路径错误
Java 进程以错误用户身份运行,轻则读不到配置文件、写不了日志,重则被 SELinux 或 systemd 安全策略拦截。
专业股权研究自动化系统,支持6,000-10,000字首发覆盖报告和3,000-5,000字季报更新报告。触发词:股票研究、深度研究、首发覆盖、季报更新、DCF估值。
-
User必须是真实存在的**系统用户**(如myapp),不能是用户名字符串或空值;创建命令推荐:sudo useradd -r -s /sbin/nologin myapp -
WorkingDirectory要设成 jar 包所在目录(如/opt/myapp),不是用户家目录,也不是/tmp—— 否则相对路径的application.yml或日志文件会找错地方 - 赋权必须到位:
sudo chown -R myapp:myapp /opt/myapp,且确保该用户对 JVM 二进制、jar、配置、日志目录都有读/执行/写权限(视情况而定)
Restart=always 不等于“永远能重启成功”
这个配置只控制 systemd 的行为,不解决根本问题。很多服务看似启了又挂,其实是 JVM 启动失败后立即退出,systemd 只是机械地重试。
- 加
RestartSec=10是为了防风暴重启,但更要配StartLimitInterval=60和StartLimitBurst=5,否则连续失败 5 次后 systemd 会彻底放弃 - 务必打开日志:用
StandardOutput=journal和StandardError=journal,然后查日志:sudo journalctl -u myapp.service -n 50 -f - 常见静默失败原因:JVM 参数错(如
-Xmx2g但物理内存只有 1G)、端口被占、logback.xml里路径写死成/home/user/logs、缺少 native 库(如 JNA)
为什么 systemctl enable 后还是不自启
最常漏掉的一步是 daemon-reload。改完 .service 文件后,systemd 根本不知道有新东西。
- 顺序不能错:改完文件 →
sudo systemctl daemon-reload→sudo systemctl enable myapp.service→sudo systemctl start myapp.service -
enable只是建软链接(到/etc/systemd/system/multi-user.target.wants/),不校验文件语法;可用sudo systemctl cat myapp.service确认内容已加载 - 检查是否真启用:
sudo systemctl is-enabled myapp.service输出必须是enabled,不是static或disabled
最容易被忽略的点是:Java 应用启动耗时长(比如 Spring Boot 初始化慢),但 Type=simple 默认认为进程一启动就“就绪”。如果应用需要 30 秒才真正监听端口,systemd 可能误判为启动失败而杀掉它——这时得加 TimeoutStartSec=120 或改用 Type=notify 配合 spring-boot-starter-systemd。










