日期:2014-05-16  浏览次数:20906 次

关于Apache Common Daemon 守护进程

转自 http://www.douban.com/note/128672313/

Java语言自1994年出现至今,初期是作为客户端与网页Applet形式来发展的,后来慢慢进化为服务器端开发语言。但是因为Java的可移植性,它必须运行在JVM上,且以进程方式运行,所以对Java程序生命周期的管理较为麻烦。尤其当Java程序需要以守护进程形式,长期在后台运行时,更是如此。
试想对一个Java程序,根据不同的时间阶段(如生命周期的不同阶段),使其执行不同功能(如init,start,stop,destroy等);或者在一个Java程序退出前,执行一段代码,完成某些功能;又或者监控一个Java程序,在其Crashed后,立即重启该程序等等。以上这些情况都是比较棘手的。第一种情况——根据不同的时间阶段执行不同功能,这点可以通过Java程序开启TCP、UDP端口来监听控制信息而实现;第二种情况——在程序退出前执行特定代码,这点可以通过加载钩子函数完成;第三种情况——监控程序Crashed并重启,这点则需要额外的监控程序来完成了。以上种种不管如何实现,都说明了Java程序在后台长期运行时的一些需求与困难。Apache Common Daemon项目即是为解决这些情况,保证Java程序在后台长期运行而产生的。它源自Tomcat 4.0项目。
Apache Common Daemon分为两个部分:一部分是用C写的,与操作系统交互;另一部分是用Java写的,提供Daemon接口。

?

其使用方法也很简单:将Apache Common Daemon下载后,编译安装;将Java程序写成一个实现org.apache.commons.daemon.Daemon接口的类;执行./jsvc -cp commons-daemon.jar:my.jar MyClass即可。(其中./jsvc是在Apache Common Daemon编译安装后的目录下;commons-daemon.jar是Apche Common Daemon的Java部分;my.jar是Java程序打成的Jar包;MyClass是实现了org.apache.commons.daemon.Daemon接口的类。)如果不想实现org.apache.commons.daemon.Daemon接口,则可以另一种执行方式:将Apache Common Daemon下载后,编译安装;将Java程序写成一个类,该类包含4个方法(void init(String[] arguments)、void start()、void stop()、void destroy());执行./jsvc -cp commons-daemon.jar:my.jar MyClass即可。其实void init(String[] arguments)、void start()、void stop()、void destroy()这4个方法的签名在org.apache.commons.daemon.Daemon接口已有定义,只是init方法的参数有所不同,感兴趣的同学可以深入再看下-_-|||...
Apache Common Daemon的Java部分较为简单,就不详细说了,这一段说下C的部分。上一段说的./jsvc其实就是运行C部分。Apache Common Daemon的C部分分成3个进程运行:一个Launcher Process;、一个Controller Process、一个Controlled Process。
?

其中Controlled Process就是Java运行的进程。如果该进程Crashed了,则Controller Process会在下一分钟重新启动一个Controlled Process运行。整个C部分的入口是jsvc-unix.c文件的main函数,这也是Launcher Process的启动入口。在jsvc-unix.c文件的1017行,通过fork()函数生成Controller Process,然后Launcher Process即结束运行(也可等待,这里不详细描述了)。Controller Process在run_controller函数中,通过fork()(jsvc-unix.c文件的1060行)函数生成Controlled Process。Controlled Process调用child函数来完成Java程序的运行(jsvc-unix.c文件的1065行)。在child函数中,Controlled Process分别调用java.c文件中的java_init()、java_start()、java_stop()、java_destroy()等方法,实现对Java程序的控制。以上四个方法的实现中,主要逻辑类似如下代码(这里以java_stop()为例):

method = (*env)->GetStaticMethodID(env, cls, stop, stopparams);
if (method == NULL) {
??? log_error("Cannot found Daemon Loader \"stop\" entry point");
??? return false;
}

ret = (*env)->CallStaticBooleanMethod(env, cls, method);

这里*env是JNIEnv类型的变量,具体我还没有细看-_-|||...
以上就是对Apache Common Daemon的一个大概了解。