jsvc - 用common-deamon构建java后台服务

在我们日常开发中,单独启一个java进程来处理业务是至关重要的。试想对一个Java程序,根据不同的时间阶段(如生命周期的不同阶段),使其执行不同功能(如init,start,stop,destroy等);或者在一个Java程序退出前,执行一段代码,完成某些功能等等。


Commons Daemon 可以帮你实现将一个普通的 Java 应用编程系统的一个后台服务。例如 Tomcat就是利用这个项目来实现作为 Linux 和 Windows 的服务启动和停止的。
官网地址:http://commons.apache.org/proper/commons-daemon/
Apache Common Daemon分为两个部分:一部分是用C写的,与操作系统交互;另一部分是用Java写的,提供Daemon接口。


下面是构建java后台服务的小Demo过程(基于Linux)

1、安装commons-daemon
         wget http://mirror.bit.edu.cn/apache//commons/daemon/source/commons-daemon-1.0.15-src.tar.gz
         tar -xzvf commons-daemon-1.0.15-src.tar.gz 
          cd  commons-daemon-1.0.15-src/src/native/unix
          sh support/buildconf.sh
          ./configure --with-java=/home/jdk (jdk home)
          make

2、编写服务启动类HelloService.java
import org.apache.commons.daemon.Daemon;
import org.apache.commons.daemon.DaemonContext;
import org.apache.commons.daemon.DaemonInitException;

public class HelloService implements Daemon {

	private static boolean isStop = false;
	
	@Override
	public void init(DaemonContext arg0) throws DaemonInitException, Exception {
		System.out.println("初始化...");
	}

	@Override
	public void start() throws Exception {
		System.out.println("开始执行...");
		createFile("start");
		while (!isStop) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {

			}
			System.out.println("running");
		}
	}

	@Override
	public void stop() throws Exception {
		System.out.println("停止执行...");
		isStop=true;
	}
	
	@Override
	public void destroy() {
		System.out.println("销毁...");
	}
	
	
}
ps:该类中实现了Daemon的init、start、stop、destroy方法,当然也可以不实现Daemon接口,但服务类中必须定义这四个方法。服务在启动时会先调用init方法,再调用start方法;服务停止时会先调用stop方法,再调用destroy方法。

3、将该类打包成HelloService.jar
4、编写服务脚本 HelloDaemon.sh
#!/bin/sh

JAVA_HOME=/home/jdk
DAEMON_HOME=/home/server/commons-daemon-1.0.15-src
DAEMON_USER=web

CLASSPATH=\
$DAEMON_HOME/commons-daemon-1.0.15.jar:\
$DAEMON_HOME/HelloService.jar:\

PATH=$PATH:$DAEMON_HOME/src/native/unix
export PATH

# for multi instances adapt those lines.
TMP_DIR=/var/tmp
PID_FILE=/var/run/tlstat.pid


case "$1" in
start)
$DAEMON_HOME/src/native/unix/jsvc \
    -user $DAEMON_USER \
    -home $JAVA_HOME \
    -pidfile $PID_FILE \
    -wait 90 \
    -outfile /tmp/HelloDaemon.out \
    -errfile '&1' \
    -cp $CLASSPATH \
    HelloService  
 

echo "result: $?"
exit $?
;;


stop)
$DAEMON_HOME/src/native/unix/jsvc \
-stop \
-pidfile $PID_FILE \
HelloService
exit $?
;;


*)
echo "Usage jsvc start/stop"
exit 1;;
esac
ps:下载commons-daemon-1.0.15.jar 放到根目录

5、服务启动与关闭
    启动命令: ./HelloDaemon.sh start
    关闭命令:./HelloDaemon.sh stop
    观察输出的日志/tmp/HelloDaemon.out ;观察下linux中的进程

附:
当这样运行的时候,在停止服务的时候会失败
Service exit with return value 143
查阅资料得如下说明:
It turns out that the jsvc stop command was behaving correctly. I had to dig into the way that processes receive termination messages in Linux/Unix via the kill command. Jsvc issues a kill -15 (which is a soft kill) on the daemon. See: http://commons.apache.org/daemon/ and http://en.wikipedia.org/wiki/Kill_(command) for the description of how unix processes receive messages.

The real issue was in the construction of the daemon. In my start method, the daemon looped until a shutdown command was issued, which prevented the daemon from giving up control as the daemon child process.

I had this:

@Override
public void start() 
{
    doStartWork();
    while (isAlive()) 
    {
        Thread.sleep(1000); 
    }
}
I should have had below, so I could return and allow the daemon thread to receive signals from the OS. See http://commons.apache.org/daemon/jsvc.html#How_jsvc_works, sepcifically the section under: 'Controlled process:'
@Override
public void start() 
{
    doStartWork();
}
修改后可正常停止服务!

你可能感兴趣的:(jsvc - 用common-deamon构建java后台服务)