必须用绝对路径写死Java可执行文件,因为systemd不加载用户shell环境,PATH未包含java,which java等命令无效;Environment=只影响进程变量,不改变命令查找路径;需用readlink -f $(which java)确认真实路径。

必须在 ExecStart 中写死 Java 可执行文件的绝对路径,不能只写 java。
为什么不能用 java 命令名
systemd 启动服务时默认不加载用户 shell 的环境(比如 ~/.bashrc),所以 $PATH 里没有 java,which java 或 command -v java 的结果也无效。哪怕你配置了 JAVA_HOME,systemd 也不会自动把它加进 PATH。
常见错误现象:Failed to start myapp.service: Unit myapp.service has a bad unit file. 或启动后日志里报 java: command not found。
- systemd 的
Environment=只影响服务进程环境变量,不影响命令查找路径 -
ExecStartPre里调用java -version同样会失败,除非也写绝对路径 - 即使系统级
/etc/profile.d/java.sh已存在,对 systemd 无效
怎么找并验证 Java 绝对路径
别猜,别依赖 which java 输出——它可能指向 /usr/bin/java 这种符号链接,而 systemd 不会自动解析。得找到真实二进制路径。
跨平台内容管理系统构建与修改工作流(WordPress、Shopify、Wix、Squarespace、Drupal、WooCommerce、Joomla、HubSpot CMS Hub、Web…)
- 运行
readlink -f $(which java),输出类似/usr/lib/jvm/java-17-openjdk-amd64/bin/java - 或者用
sudo update-alternatives --config java,选中后看提示行末尾的完整路径(去掉/bin/java就是JAVA_HOME,拼上/bin/java就是你要的ExecStart路径) - 手动检查:确认该路径下文件存在且可执行:
ls -l /usr/lib/jvm/java-17-openjdk-amd64/bin/java
myapp.service 中 ExecStart 的正确写法
假设你的 JAR 是 /opt/myapp/app.jar,Java 实际路径是 /usr/lib/jvm/java-17-openjdk-amd64/bin/java,那么:
ExecStart=/usr/lib/jvm/java-17-openjdk-amd64/bin/java -Dspring.profiles.active=prod -jar /opt/myapp/app.jar
注意几点:
- 不要在
ExecStart前加sudo或su—— systemd 以 root 运行时不需要,以普通用户运行时应配User=和Group= - 如果用了非系统自带 JDK(比如手动解压到
/opt/jdk-17.0.1),路径必须完整写出:/opt/jdk-17.0.1/bin/java - 参数顺序无关,但
-jar必须紧跟在java命令之后,不能被其他 JVM 参数隔开
最容易被忽略的一点:JDK 升级或重装后,/usr/lib/jvm/ 下的子目录名可能变(比如从 java-17-openjdk-amd64 变成 java-17-openjdk-x86_64),systemd 不会自动更新——得人工检查并同步改 ExecStart。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










