ActiveMQ 和Commons-Daemon整合

            在一般的java项目中,如果在linux中实现进程在后台执行比较简单,可以采用nohup cmd 或者sh cmd &等多种方式实现,进行在后台执行。但是在window操作系统中就比较困难了,需要实现相关的类。如在tomcat,jboss的启动之后,端口一直开放着。

          常用实现方式实现Commons-Daemon中的Daemon接口实现相关的方式,使用相关的bat,命令启动。在Commons-Deamon调用jsvc实现。

 

 

 

 

在activemq.bat中相关bat命令如下:

 

"%_JAVACMD%" %SUNJMX% %ACTIVEMQ_DEBUG_OPTS% %ACTIVEMQ_OPTS% %SSL_OPTS% -Dactivemq.classpath="%ACTIVEMQ_CLASSPATH%" -Dactivemq.home="%ACTIVEMQ_HOME%" -Dactivemq.base="%ACTIVEMQ_BASE%" -jar "%ACTIVEMQ_HOME%/bin/run.jar" start %*

备注:在run.jar包中Main方法调用 ActiveMQLauncher 实现相关的功能。

 

Starting jsvc
To check the allowed parameters for the jsvc binary simply do: 

./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:
            'client' 'server'
    -cp / -classpath <directories and zip/jar files>
        set search path for service classes and resouces
    -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
    -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 (works only for Linux)
    -wait <waittime>
        wait waittime seconds for the service to start
        waittime should multiple of 10 (min=10)
    -stop
        stop the service using the file given in the -pidfile option
    -keepstdin
        does not redirect stdin to /dev/null

 

 

 

实际上仅支持类UNIX平台。源代码在A src/native/unix subdirectory子目录。在将来将利用APR来提供更方便的平台支持。

从源代码构建

在UNIX系统下构建你需要:

    ● GNU AutoConf (最低版本 2.53)
    ● 一个ANSI-C兼容的编译器 (推荐GCC)
    ● GNU Make
    ● JAVA2平台兼容的SDK

你需要构建 "configure" 程序:

sh support/buildconf.sh

结果类似如下:

support/buildconf.sh
support/buildconf.sh: configure script generated successfully

一旦生成了configure脚本,可进行后续步骤。

从一个发布版中构建

在UNIX系统下构建你需要:

    ● 一个ANSI-C兼容的编译器 (推荐GCC)
    ● GNU Make
    ● JAVA2平台兼容的SDK
    
你必须指定JAVA_HOME或者使用 --with-java=<dir> 参数指定JDK,再或使用JAVA_HOME环境变量指定JDK安装位置。例如:

./configure --with-java=/usr/java

或者

export JAVA_HOME
./configure

如果你的操作系统支持,configure会顺利运行,否则会报错。构建二进制程序和库:

make

这个生成可执行文件jsvc。

启动 jsvc

查看可用的jsvc参数仅需:

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

Where options include:

    -jvm <JVM name>
        use a specific Java Virtual Machine. Available JVMs: 'client' 'server'
    -cp / -classpath <directories and zip/jar files>
        set search path for service classes and resouces
    -home <directory>
        设置JDK或者JRE的安装路径 (或者设置 JAVA_HOME 环境变量)
    -version
        show the current Java environment version (to check correctness of -home and -jvm. Implies -nodetach)
    -help / -?
        显示帮助信息 (implies -nodetach)
    -nodetach
        don't detach from parent process and become a daemon
    -debug
        详细输出调试信息
    -check
        only check service (implies -nodetach)
    -user <user>
        运行守护程序的用户(默认是当前用户)
    -verbose[:class|gc|jni]
        启用详细输出
    -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>
       jsvc的pid文件位置(默认 /var/run/jsvc.pid)
    -D<name>=<value>
        设置java系统的属性
    -X<option>
        设置虚拟机参数
    -wait <waittime>
        服务启动的等待时间,是10的倍数 (最小10)
    -stop
        使用-pidfile参数指定的文件停止服务

使用 jsvc

有两种方式来使用jsvc:一种是实现了Daemon接口的类或者调用一个类包含需要的方法。例如,Tomcat-4.1.x使用了Daemon接口,Tomcat-5.0.x提供了一个包含可被jsvc直接调用的方法的类。

使用 Daemon 接口

    ● 写一个实现Daemon接口的类 (MyClass).
    ● 打包在jar文件中 (my.jar).
    ● 如下调用jsvc:

      ./jsvc -cp commons-daemon.jar:my.jar MyClass
        

直接调用

你可以写一个实现如下方法的类:

    ● void load(String[] arguments): 此处打开配置文件、创建跟踪文件、创建ServerSocket和线程
    ● void start(): 启动线程,接收连接
    ● void stop(): 通知线程激活run(), 关闭ServerSockets
    ● void destroy(): 销毁在init()中创建的对象

打包在jar文件中:

./jsvc -cp commons-daemon.jar:my.jar MyClass

jsvc如何工作

Jsvc使用3个进程: 启动进程、主控进程、被控进程。被控进程也就是主要的java线程,如果JVM崩溃,主控进程会在以后几分钟启动它。jsvc是一个守护进程,它可以以root帐号启动,-user参数允许降权到一个非特权帐号。当使用了 -wait 参数,启动进程会等待直到控制进程准备好了,否则生成控制进程即返回。

Forks in commons-daemon

启动进程:

main()
{
  fork()
  parent: wait_child(), wait until JAVA service started when the child says "I am ready".
  child: controller process.
}

主控进程:

  while (fork()) {
    parent: wait_for_child.
      if exited and restart needed continue
      else exit.
    child: exit(child()). controlled process.
  }

被控进程:

In child(): controlled process.
  init_JVM().
  load_service().
  start_service().
  say "I am ready"
  wait for signal or pool for stop
  stop_service().
  destroy_service().
  destroy_JVM().
  exit (with different codes so that parent knows if it has to restart us).

注意: 主控进程使用信号停止被控进程。

降级用户

在linux上使用兼容的setuid()/setgid()。在其他的unix上使用 setgid/initgroups 。如下:

/* as root */
init_JVM().
load_service. /*  java_load() calls the load method */
downgrade user (set_caps() or set_user_group())
/* as the user $USER (from -user $USER parameter) */
umask()
start_service. /* java_start() calls the start method */


 

如在ActiveMQ中启动类如下:

package org.apache.activemq.console;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.activemq.console.command.Command;
import org.apache.activemq.console.command.ShutdownCommand;
import org.apache.activemq.console.command.StartCommand;
import org.apache.activemq.console.CommandContext;
import org.apache.activemq.console.Main;
import org.apache.activemq.console.formatter.CommandShellOutputFormatter;
import org.apache.commons.daemon.Daemon;
import org.apache.commons.daemon.DaemonContext;

/**
 * This class launches activemq under Apache JSVC {@link http://commons.apache.org/daemon/jsvc.html}
 * 
 * @author areese
 * 
 */
public class ActiveMQLauncher implements Daemon {
    private List<String> args;

    /**
     * 
     */
    public ActiveMQLauncher() {
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.commons.daemon.Daemon#destroy()
     */
    public void destroy() {
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.apache.commons.daemon.Daemon#init(org.apache.commons.daemon.DaemonContext
     * )
     */
    public void init(DaemonContext arg0) throws Exception {
        // we need to save the args we started with.
        args = Arrays.asList(arg0.getArguments());
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.commons.daemon.Daemon#start()
     */
    public void start() throws Exception {
        CommandContext context = new CommandContext();
        context.setFormatter(new CommandShellOutputFormatter(System.out));

        Command command = new StartCommand();
        command.setCommandContext(context);

        command.execute(args);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.commons.daemon.Daemon#stop()
     */
    public void stop() throws Exception {
        CommandContext context = new CommandContext();
        context.setFormatter(new CommandShellOutputFormatter(System.out));

        Command command = new ShutdownCommand();
        command.setCommandContext(context);

        List<String> tokens = new ArrayList<String>(Arrays.asList(new String[] {
                "--jmxlocal", "--all", }));

        command.execute(tokens);
    }

}

 

 Daemon that implements the following methods:

  • void init(String[] arguments): Here open configuration files, create a trace file, create ServerSockets, Threads
  • void start(): Start the Thread, accept incoming connections
  • void stop(): Inform the Thread to terminate the run(), close the ServerSockets
  • void destroy(): Destroy any object created in init()

你可能感兴趣的:(jsvc,Commons-Daemon)