Apache Commons Daemon 常用 CLI 命令与工具详解

整理 jsvc 1.6.1 全部命令行参数为速查表并标注实测默认值,覆盖服务启动、ps 与 jps 进程验证、-pidfile 与 -stop 优雅停止、版本查询与日志查看,附八类常见报错的排查方法,全部命令实测通过。

Apache Commons DaemonApache Commons Daemon2026/10/13

Apache Commons Daemon 常用 CLI 命令与工具详解

目标:以 jsvc 1.6.1 的 --help 实测输出为基准,把全部命令行参数整理成带默认值的速查表,并给出启动、验证、停止、查日志的完整命令组合与常见报错排查,全部命令已在 Ubuntu 22.04 / CentOS 8(JDK 17 + Maven)实测通过。

一、环境信息

本文所有命令与回显在以下环境实测取得。

项目值
jsvc 版本1.6.1(Apache Commons Daemon)
操作系统Ubuntu 22.04.5 LTS(x86_64),CentOS 8 核对一致
JDKOpenJDK 17.0.20.1
示例服务DemoDaemon(实现 Daemon 接口的最小心跳服务)

两台操作系统的 jsvc --help 输出 md5 完全一致(8406a01951c7866ceb1e0f3b855ed8fb),参数体系与默认值不因发行版而异。示例统一约定:jsvc 安装于 /usr/local/bin/jsvc,服务类路径为 /opt/demo-daemon/commons-daemon-1.6.1.jar:/opt/demo-daemon,JDK 位于 /usr/lib/jvm/java-17-openjdk-amd64。

一个必须先建立的认知:jsvc 的输出重定向发生在 JVM 初始化之前,不传 -outfile/-errfile 时两者默认指向 /dev/null,这会吞掉 -version、-check 等命令的输出。本文所有需要在控制台看到结果的命令都显式携带 -outfile '&1' -errfile '&2'(含义分别为 stdout 保持原样、stderr 保持原样)。

💡 技术拓展:把 Java 程序做成守护进程有四种常见方案,选型对比如下。

方案pid 管理降权运行日志信号处理开机自启
jsvcpidfile 记录-user 参数原生支持-outfile/-errfile 重定向内建优雅停机协议需配合 systemd 或 init 脚本
prunsrvWindows 服务管理器托管服务账号/凭据配置stdout/stderr 重定向到文件Windows 服务控制协议注册为 Windows 服务即自启
systemd Unitcgroup 全程托管User= 指令journald 或重定向KillSignal 可配WantedBy= 即自启
nohup+disown需手工记录 pid需 su/runuser 自行处理需自行重定向默认无优雅停机无,需自写开机脚本

本文展开的是 jsvc 的命令行操作面;Windows 平台对应工具为 prunsrv。

二、jsvc --help 完整输出

以下为 1.6.1 的 --help 逐字实测输出(Ubuntu 22.04 与 CentOS 8 一致):

/usr/local/bin/jsvc --help

回显(实测完整输出):

Usage: jsvc [-options] class [args...]

Where options include:

    -help | --help | -?
        show this help page (implies -nodetach)
    -jvm <JVM name>
        use a specific Java Virtual Machine. Available JVMs:
            'server'
    -client
        use a client Java Virtual Machine.
    -server
        use a server Java Virtual Machine.
    -cp | -classpath <directories and zip/jar files>
        set search path for service classes and resouces
    -java-home | -home <directory>
        set the path of your JDK or JRE installation (or set
        the JAVA_HOME environment variable)
    -version
        show the current Java environment version (to check
        correctness of -home and -jvm. Implies -nodetach)
    -showversion
        show the current Java environment version (to check
        correctness of -home and -jvm) and continue execution.
    -nodetach
        don't detach from parent process and become a daemon
    -debug
        verbosely print debugging information
    -check
        only check service (implies -nodetach)
    -user <user>
        user used to run the daemon (defaults to current user)
    -verbose[:class|gc|jni]
        enable verbose output
    -cwd </full/path>
        set working directory to given location (defaults to /)
    -outfile </full/path/to/file>
        Location for output from stdout (defaults to /dev/null)
        Use the value '&2' to simulate '1>&2'
    -errfile </full/path/to/file>
        Location for output from stderr (defaults to /dev/null)
        Use the value '&1' to simulate '2>&1'
    -pidfile </full/path/to/file>
        Location for output from the file containing the pid of jsvc
        (defaults to /var/run/jsvc.pid)
    -D<name>=<value>
        set a Java system property
    -X<option>
        set Virtual Machine specific option
    -ea[:<packagename>...|:<classname>]
    -enableassertions[:<packagename>...|:<classname>]
        enable assertions
    -da[:<packagename>...|:<classname>]
    -disableassertions[:<packagename>...|:<classname>]
        disable assertions
    -esa | -enablesystemassertions
        enable system assertions
    -dsa | -disablesystemassertions
        disable system assertions
    -agentlib:<libname>[=<options>]
        load native agent library <libname>, e.g. -agentlib:hprof
    -agentpath:<pathname>[=<options>]
        load native agent library by full pathname
    -javaagent:<jarpath>[=<options>]
        load Java programming language agent, see java.lang.instrument
    -procname <procname>
        use the specified process name
    -wait <waittime>
        wait waittime seconds for the service to start
        waittime should multiple of 10 (min=10)
    -restarts <maxrestarts>
        maximum automatic restarts (integer)
        -1=infinite (default), 0=none, 1..(INT_MAX-1)=fixed restart count
    -stop
        stop the service using the file given in the -pidfile option
    -keepstdin
        does not redirect stdin to /dev/null
    --add-modules=<module name>
        Java 9 --add-modules option. Passed as it is to JVM
    --module-path=<module path>
        Java 9 --module-path option. Passed as it is to JVM
    --upgrade-module-path=<module path>
        Java 9 --upgrade-module-path option. Passed as it is to JVM
    --add-reads=<module name>
        Java 9 --add-reads option. Passed as it is to JVM
    --add-exports=<module name>
        Java 9 --add-exports option. Passed as it is to JVM
    --add-opens=<module name>
        Java 9 --add-opens option. Passed as it is to JVM
    --limit-modules=<module name>
        Java 9 --limit-modules option. Passed as it is to JVM
    --patch-module=<module name>
        Java 9 --patch-module option. Passed as it is to JVM
    --illegal-access=<value>
        Java 9 --illegal-access option. Passed as it is to JVM.
        Refer java help for possible values.
    --enable-preview
        Java 11 --enable-preview option. Passed as it is to JVM
    --enable-native-access=<module name>
        Java 17 --enable-native-access option. Passed as it is to JVM

jsvc (Apache Commons Daemon) 1.6.1
Copyright (c) 1999-2026 Apache Software Foundation.

注意命令尾部会自动打印版本横幅,因此 --help | tail -2 也是最轻量的版本确认手段。

三、参数速查表

下表覆盖 --help 全部参数,默认值一栏均来自 help 原文或实测确认。

参数作用默认值备注
-help、--help、-?显示帮助并退出无隐含 -nodetach
-jvm <name>指定 JVM 名称serverJDK 17 下仅 server 可用,-client 实测报 Invalid JVM name
-client / -serverclient 或 server JVM 简写server现代 JDK 无 client VM
-cp、-classpath类与资源搜索路径无(必填项之一)冒号分隔,可混 jar 与目录
-java-home、-homeJDK/JRE 目录JAVA_HOME 环境变量或系统 default-java多 JDK 机器必须显式指定
-version打印 Java 环境与 commons daemon 版本后退出无隐含 -nodetach,且必须带类名参数
-showversion打印版本后继续启动无常用于排查 JVM 选择问题
-nodetach前台运行不脱离终端后台脱离Ctrl-C 或 SIGTERM 走优雅停机
-debug全流程调试输出关闭输出参数转储与生命周期日志
-check仅预检查服务加载无隐含 -nodetach,输出 checked successfully
-user <user>运行身份当前用户仅 root 可用;pidfile 在降权前由 root 写入
-verbose[:classgcjni]JVM 详细输出
-cwd <path>工作目录/实测 /proc/<pid>/cwd 可验证
-outfile <path>stdout 去向/dev/null特殊值 &2(转 stderr)与 SYSLOG
-errfile <path>stderr 去向/dev/null特殊值 &1(转 stdout)与 SYSLOG
-pidfile <path>pid 文件位置/var/run/jsvc.pid含存活检测与文件锁,正常停止后自动删除
-D<name>=<value>Java 系统属性无自动注入 commons.daemon.process.id 等内置属性
-X<option>JVM 专有参数无如 -Xms256m -Xmx512m
-ea / -da(含包限定)启用/禁用断言禁用透传 JVM
-esa / -dsa启用/禁用系统断言禁用透传 JVM
-agentlib / -agentpath / -javaagent加载 agent无透传 JVM,错误由 JVM 报出
-procname <name>进程改名jsvc.exec便于按名检索与监控
-wait <seconds>等待启动完成不等待须为 10 的倍数且最小 10
-restarts <count>自动重启上限-1(无限)0 为禁用;两次重启间隔至少 60 秒
-stop按 pidfile 停止无必须带类名参数
-keepstdin保留 stdinstdin 重定向到 /dev/null交互式服务才需要
--add-modules 等模块化系列JPMS 参数透传无Java 9+,原样透传 JVM
--enable-preview预览特性关闭Java 11+
--enable-native-access本地访问声明无Java 17

四、启动服务与运行验证

4.1 标准启动命令

root 启动、-user appuser 降权、堆 256 至 512MB、日志与 pidfile 显式落盘:

sudo /usr/local/bin/jsvc -java-home /usr/lib/jvm/java-17-openjdk-amd64 -cp /opt/demo-daemon/commons-daemon-1.6.1.jar:/opt/demo-daemon -user appuser -Xms256m -Xmx512m -outfile /opt/demo-daemon/demo-stdout.log -errfile /opt/demo-daemon/demo-stderr.log -pidfile /opt/demo-daemon/demo-daemon.pid DemoDaemon
echo RC=$?

回显(实测):

RC=0

4.2 进程层验证:ps

ps -ef | grep jsvc | grep -v grep

回显(实测,root 控制进程加 appuser JVM 子进程):

root        6749       1  0 07:51 ?        00:00:00 jsvc.exec -java-home /usr/lib/jvm/java-17-openjdk-amd64 -cp /opt/demo-daemon/commons-daemon-1.6.1.jar:/opt/demo-daemon -user appuser -Xms256m -Xmx512m -outfile /opt/demo-daemon/demo-stdout.log -errfile /opt/demo-daemon/demo-stderr.log -pidfile /opt/demo-daemon/demo-daemon.pid DemoDaemon
appuser     6750    6749  1 07:51 ?        00:00:00 jsvc.exec -java-home /usr/lib/jvm/java-17-openjdk-amd64 -cp /opt/demo-daemon/commons-daemon-1.6.1.jar:/opt/demo-daemon -user appuser -Xms256m -Xmx512m -outfile /opt/demo-daemon/demo-stdout.log -errfile /opt/demo-daemon/demo-stderr.log -pidfile /opt/demo-daemon/demo-daemon.pid DemoDaemon

设置了 -procname 时进程名会替换 jsvc.exec,例如 -procname demo-app 后 ps 显示(实测):

root        6878       1  0 07:52 ?        00:00:00 demo-app -java-home /usr/lib/jvm/java-17-openjdk-amd64 -procname demo-app -cp /opt/demo-daemon/commons-daemon-1.6.1.jar:/opt/demo-daemon -outfile /opt/demo-daemon/demo-stdout.log -errfile /opt/demo-daemon/demo-stderr.log -pidfile /opt/demo-daemon/demo-daemon.pid -wait 20 DemoDaemon --env production port=8080

4.3 JVM 层验证:jps

jps -l

回显(实测):

6779 jdk.jcmd/sun.tools.jps.Jps
6750 DemoDaemon

CentOS 8 的 jps 不在默认 PATH,使用完整路径 /usr/lib/jvm/java-17-openjdk/bin/jps -l,实测同样能列出 DemoDaemon 主类进程。

4.4 pidfile 验证

cat /opt/demo-daemon/demo-daemon.pid

回显(实测):

6750

pidfile 中的值就是 JVM 子进程的 pid,可直接用于 jcmd 观测。实测验证堆参数已生效:

jcmd $(cat /opt/demo-daemon/demo-daemon.pid) VM.flags | tr ' ' '\n' | grep -E 'InitialHeapSize|MaxHeapSize'

回显(实测):

-XX:InitialHeapSize=268435456
-XX:MaxHeapSize=536870912

五、停止服务

标准停止命令(-stop 加 -pidfile 加类名三者缺一不可):

sudo /usr/local/bin/jsvc -stop -pidfile /opt/demo-daemon/demo-daemon.pid DemoDaemon
echo RC=$?

回显(实测):

RC=0

停止后三重确认:进程消失、日志收尾完整、pidfile 自动删除。

jps -l

回显(实测,仅剩 jps 自身):

6848 jdk.jcmd/sun.tools.jps.Jps
tail -4 /opt/demo-daemon/demo-stdout.log

回显(实测):

[DemoDaemon] heartbeat #6, thread=demo-worker
[DemoDaemon] stop() called, notifying worker to exit
[DemoDaemon] worker thread exited
[DemoDaemon] destroy() called, resources released
ls -l /opt/demo-daemon/demo-daemon.pid

回显(实测):

ls: cannot access '/opt/demo-daemon/demo-daemon.pid': No such file or directory

两个实测坑:其一,-stop 缺类名直接失败(No class specified);其二,-stop 找不到 pidfile 时返回 255 并报 Cannot open PID file(实测回显见第八章)。

六、版本与预检查命令

6.1 -version

打印 jsvc 版本、Java 环境与 commons daemon 版本后退出。必须显式携带类名与控制台输出参数:

/usr/local/bin/jsvc -version -outfile '&1' -errfile '&2' -java-home /usr/lib/jvm/java-17-openjdk-amd64 -cp /opt/demo-daemon/commons-daemon-1.6.1.jar:/opt/demo-daemon DemoDaemon

回显(实测):

jsvc (Apache Commons Daemon) 1.6.1
Copyright (c) 1999-2026 Apache Software Foundation.
java version "17.0.20.1"
OpenJDK Runtime Environment (build 17.0.20.1+1-1-22.04-Ubuntu)
OpenJDK 64-Bit Server VM (build 17.0.20.1+1-1-22.04-Ubuntu, mixed mode, sharing)
commons daemon version "1.6.1"
commons daemon process (id: 6525, parent: 6524)

6.2 -showversion

与 -version 信息一致,但打印后继续启动服务。实测回显中版本横幅之后紧接 init() 与心跳日志(见配置参数详解篇 8.4 节的完整实测输出)。

6.3 -check

部署前的加载预检查,验证类路径与主类可被 DaemonLoader 解析:

/usr/local/bin/jsvc -check -java-home /usr/lib/jvm/java-17-openjdk-amd64 -outfile '&1' -errfile '&2' -cp /opt/demo-daemon/commons-daemon-1.6.1.jar:/opt/demo-daemon DemoDaemon

回显(实测):

Service "DemoDaemon" checked successfully

6.4 默认 pidfile 位置

不传 -pidfile 时实例把 pid 写到 /var/run/jsvc.pid(help 默认值的实测确认):

cat /var/run/jsvc.pid

回显(实测):

7056

七、日志文件查看

7.1 -outfile 与 -errfile 文件

心跳与业务日志实时追加在 -outfile 指定的文件中:

cat /opt/demo-daemon/demo-stdout.log

回显(实测):

[DemoDaemon] init() called, args=[]
[DemoDaemon] start() called, worker thread starting
[DemoDaemon] heartbeat #1, thread=demo-worker

文件由 root 在降权前打开,属主为 root 且权限 600(实测 ls -l 显示 -rw------- 1 root root)。追踪日志用 tail -f /opt/demo-daemon/demo-stdout.log。

7.2 systemd 托管时的 journald

以 systemd Type=forking 单元托管 jsvc 时,ExecStart 的 stdout 仍受 -outfile 控制;纯 Java 形态(不经 jsvc)的 stdout 由 journald 收集:

journalctl -u demo-plain.service --no-pager -n 3 | tail -3

回显(实测):

Oct 13 08:10:35 1a283e06d6da systemd[1]: Started DemoMain Service (plain java + systemd).
Oct 13 08:10:35 1a283e06d6da java[9705]: [DemoMain] main() started, args=[]
Oct 13 08:10:40 1a283e06d6da java[9705]: [DemoMain] heartbeat #1

7.3 -debug 控制台调试

-debug 把参数解析、JVM 创建、类加载全流程打到 stderr,定位启动问题时最有用。实测节选:

+-- DUMPING JAVA VM CREATION ARGUMENTS -----------------
| Extra options:                 1
|   "-Djava.class.path=/opt/demo-daemon/commons-daemon-1.6.1.jar:/opt/demo-daemon" (0x00000000)
+-------------------------------------------------------
Java VM created successfully
Class org/apache/commons/daemon/support/DaemonLoader found
Native methods registered

八、常见报错速查

以下报错信息全部为实测原文,可直接对照排查。

报错信息触发场景解法
JSVC re-exec requires execution with an absolute or relative path用裸命令名 jsvc 调用改用绝对路径如 /usr/local/bin/jsvc
No class specified / Cannot parse command line arguments-version 或 -stop 未带类名命令尾部补上主类名
Invalid option --version传入 jsvc 不认识的选项(注意 -version 是合法的,双横线 --version 不是)对照第二章 help 输出修正拼写
java.lang.ClassNotFoundException: NoSuchClass-cp 配置错误或类名写错核对 -cp 路径与类全名,可用 -check 预检
UnsupportedClassVersionError class file version 61.0 this version only up to 55.0jsvc 落到低版本 JVM(如系统默认 Java 11)显式传 -java-home 指向 JDK 17
Cannot open PID file /var/run/jsvc.pid, PID is 7205非 root 运行且无默认 pidfile 写权限,或 pidfile 目录不存在显式指定可写位置的 -pidfile
Cannot set group id for user 'root' / Error validating user 'root'非 root 用户使用 -user 切换他人身份-user 仅限 root 使用
Invalid JVM name specified client / Cannot locate JVM library fileJDK 17 下使用 -client去掉 -client,现代 JDK 仅有 server VM
Service exit with a return value of 2服务启动阶段失败(如类版本不匹配)结合 -errfile 定位栈信息

九、参考链接

  1. Apache Commons Daemon 官方主页:https://commons.apache.org/proper/commons-daemon/
  2. jsvc 启动器文档(含参数说明):https://commons.apache.org/proper/commons-daemon/jsvc.html
  3. 官方下载目录(bin 包与 src 包):https://downloads.apache.org/commons/daemon/
  4. Daemon 接口 Javadoc:https://commons.apache.org/proper/commons-daemon/apidocs/org/apache/commons/daemon/Daemon.html
  5. Maven Central 上的 commons-daemon 构件:https://repo1.maven.org/maven2/commons-daemon/commons-daemon/