java服務安裝(二):使用commons-daemon

tags: java daemonhtml


一、概述

1.一、爲何使用commons daemon

上一篇已對使用java service wrapper工具與java程序集成進行了講解,java service wrapper使用簡單,集成方法簡單,不修改任何代碼,通常狀況下已知足需求。java

可是,java service wrapper只對java程序的開啓及關閉進行操做, 若須要對程序啓動前及關閉前進行一些自定義的操做(如啓動時初始化工做,關閉時釋放某些資源或進行特殊操做),此時就可使用apache commons daemon了。linux

1.二、commons daemon介紹

Apache common deamon是用來提供java服務的安裝,實現將一個普通的 Java 應用變成系統的一個後臺服務,在linux下部署爲後臺運行程序,在windows部署爲windows服務(著名的tomcat就是使用它實現啓動及中止的。提供啓動、中止、卸載等操做)。詳細介紹可見commons-daemon官網。相對java service wrapper,commons daemon須要本身寫少量代碼,即按規定要求編寫程序啓動及關閉的入口類,僅此而已。git

1.三、本文主要內容

本文主要講解兩部份內容:github

  • linux下使用commons-daemon把java安裝爲後臺運行程序
  • windows下使用commons-daemon把java安裝爲windows服務

二、程序示例

本文示例程序與上一篇的示例(log4j+java service wrapper)放在同一工程(所以上一篇的示例本程序也適用),不過改成使用logback+commons-daemon。程序結構以下:
apache

程序結構

說明:

  • 主要DaemonMainClassForLinux、DaemonMainClassForWindows及LogbackFileLogger類及logback.xml,其它的(WrapperMainClassForWindows、FileLogger及log4j.properties)是屬於上一篇的示例。
  • install目錄是用於對程序封裝爲服務的,即存放wrapper或daemon的,daemon目錄下有linux及windows的安裝內容
  • src/main/assembly下存放打包成自定義格式的maven配置(分別是linux及windows)
  • pom.xml配置打包插件信息

使用assembly打包,打包出windows包及linux包,包結構是bin,classes和lib三個目錄,分別是安裝目錄,java程序,依賴包,以下所示:
windows

打包結果

包結構

三、linux下使用commons-daemon

linux下使用commons-daemon主要經過commons-daemon主程序及jsvc實現。本示例環境是centos6.5。centos

3.一、下載commons-daemon

commons-daemon官網下載,其中須要下載commons-daemon主程序和jsvc包(源碼包)。以下圖:
tomcat

commons daemon下載

  • 下載commons-daemon-1.0.15-bin.tar.gz,解壓出commons-daemon-1.0.15.jar放到程序目錄中(本示例爲install/daemon),以便使用。
  • 下載commons-daemon-1.0.15-src.tar.gz源碼包,此程序用於在linux下使用源碼方式安裝jsvc。(提醒:在官網的jsvc只講解了如休安裝及使用,源碼須要在這裏下載)。

3.二、安裝jsvc

可先查看官網的jsvc,本示例中安裝以下:把commons-daemon源碼包放到/opt目錄下。操做以下:bash

[root@localhost]# cd /opt/jsvc
[root@localhost jsvc]# unzip commons-daemon-1.0.15-src.zip
[root@localhost jsvc]# cd /opt/jsvc/commons-daemon-1.0.15-src/src/native/unix
[root@localhost unix]# ./configure --with-java=/usr/java/jdk1.8.0_51
*** All done ***
Now you can issue "make"
[root@localhost unix]# make
gcc   jsvc-unix.o libservice.a -ldl -lpthread -o ../jsvc
make[1]: 離開目錄「/opt/jsvc/commons-daemon-1.0.15-src/src/native/unix/native」
複製代碼

說明

  • 確保linux上已安裝java,安裝需依賴java,如上述操做中--with-java=/usr/java/jdk1.8.0_51
  • make完後,會在commons-daemon-1.0.15-src/src/native/unix下生成jsvc文件以下圖:
    jsvc
  • 記住此jsvc路徑,安裝時使用。

3.三、編寫程序入口類

程序實際的功能很簡單,以下(見LogbackFileLogger類):

public class LogbackFileLogger {
	private static Logger logger = LoggerFactory.getLogger(LogbackFileLogger.class);

	public void logInfo2file() {
		for (int i = 0; i < 50; i++) {
			logger.info("個人測試:my test{}", i);
			try {
				//睡眠一秒以維持服務運行
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				logger.error(e.getMessage(),e);
			}
		}
	}
}
複製代碼

入口類只須要實現init,destroy,start,stop方法便可,安裝時指定此類,jsvc會根據這些方法進行初始化、啓動、關閉等操做。程序以下:

/** * Linux服務安裝入口類 * * @author mason * */
public class DaemonMainClassForLinux {
	public static void init(String[] args) {
		//日誌輸出到程序根目錄(classpath)
		MainClass.initWorkDir();
	}

	public static void destroy() {
	}

	public static void start() {
		LogbackFileLogger logger = new LogbackFileLogger();
		logger.logInfo2file();
	}

	public static void stop() {
		System.exit(0);
	}
}
複製代碼

說明:

  • init方法有參數,destroy、start及stop方法無參。
  • 本示例中的初始化MainClass.initWorkDir();用於指定日誌輸出的目錄。
  • start方法做啓動入口,stop方法爲關閉,本示例簡單退出程序,若須要自定義操做,可在此方法編寫便可。

3.四、編寫安裝腳本

安裝腳本在示例install/daemon/linux下,主要設置程序名稱,路徑,jsvc路徑,java路徑,程序入口類,日誌輸出目錄便可。詳細以下:

#!/bin/sh
# description: jsw-test
# processname: jsw-test
# chkconfig: 234 20 80

# 程序名稱
SERVICE_NAME=jsw-test
#程序路徑獲取相對路徑,可填寫絕對路徑,如APP_HOME=/usr/local/bingo_cdp/deploy/bingo-cdp-timerjob-linux
APP_HOME=$(dirname $(pwd))
EXEC=/opt/jsvc/commons-daemon-1.0.15-src/src/native/unix/jsvc
JAVA_HOME=/usr/java/jdk1.8.0_51

#依賴路徑
cd ${APP_HOME}
CLASS_PATH="$PWD/classes":"$PWD/lib/*"

#程序入口類
CLASS=main.DaemonMainClassForLinux

#程序ID文件
PID=${APP_HOME}/${SERVICE_NAME}.pid
#日誌輸出路徑
LOG_OUT=${APP_HOME}/logs/${SERVICE_NAME}.out
LOG_ERR=${APP_HOME}/logs/${SERVICE_NAME}.err

#輸出
echo "service name: $SERVICE_NAME"
echo "app home: $APP_HOME"
echo "jsvc: $EXEC"
echo "java home: $JAVA_HOME"
echo "class path: $CLASS_PATH"
echo "main class: $CLASS"

#執行
do_exec()
{
    $EXEC -home "$JAVA_HOME" -Dsun.jnu.encoding=UTF-8 -Dfile.encoding=UTF-8 -Djcifs.smb.client.dfs.disabled=false -Djcifs.resolveOrder=DNS -Xms512M -Xmx1024M -cp $CLASS_PATH -outfile $LOG_OUT -errfile $LOG_ERR -pidfile $PID $1 $CLASS
}

#根據參數執行
case "$1" in
    start)
        do_exec
        echo "${SERVICE_NAME} started"
            ;;
    stop)
        do_exec "-stop"
        echo "${SERVICE_NAME} stopped"
            ;;
    restart)
        if [ -f "$PID" ]; then
            do_exec "-stop"
            do_exec
            echo "${SERVICE_NAME} restarted"
        else
            echo "service not running, will do nothing"
            exit 1
        fi
            ;;
    status)
		ps -ef | grep jsvc
		;;
    *)
	    echo "usage: service ${SERVICE_NAME} {start|stop|restart|status}" >&2
	    exit 3
	    ;;
esac
複製代碼

通常還須要把程序做爲系統服務開機啓動,所以本示例中提供了set_auto_start.sh文件,注意修改相應的文件名稱:

#!/bin/bash 
DAEMON_HOME=$(pwd)
AUTO_RUN_FILE=${DAEMON_HOME}/jsw-test.sh
AUTO_RUN_FILE_NAME=jsw-test

echo "設置${AUTO_RUN_FILE_NAME}開機啓動......"

#若文件不存在,報錯、不然設置開機啓動
if [ ! -f "${AUTO_RUN_FILE}" ]; then 
	echo "${AUTO_RUN_FILE} 不存在,請檢查文件!"
else
	\cp -f ${AUTO_RUN_FILE} /etc/init.d/${AUTO_RUN_FILE_NAME}
	chmod 777 /etc/init.d/${AUTO_RUN_FILE_NAME} 
	chkconfig --add ${AUTO_RUN_FILE_NAME} 
	chkconfig ${AUTO_RUN_FILE_NAME} on 
fi

echo "設置${AUTO_RUN_FILE_NAME}開機啓動結束"

複製代碼

3.五、程序打包及啓動

使用maven的assembly插件打包,流程可見上一篇,當前示例打linux的zip包,具體配置以下: pom.xml

<execution>
	<id>make-daemon-linux-zip</id>
	<phase>package</phase>
	<goals>
		<goal>single</goal>
	</goals>
	<configuration>
		<finalName>jsw-test</finalName>
		<appendAssemblyId>true</appendAssemblyId>
		<outputDirectory>${project.build.directory}</outputDirectory>
		<descriptors>
			<descriptor>src/main/assembly/daemon-linux-zip.xml</descriptor>
		</descriptors>
	</configuration>
</execution>
複製代碼

daemon-linux-zip.xml

<assembly>
	<id>deamon-linux</id>
	<formats>
		<format>zip</format>
	</formats>
	<includeBaseDirectory>false</includeBaseDirectory>
	<dependencySets>
		<dependencySet>
			<useProjectArtifact>false</useProjectArtifact>
			<outputDirectory>/lib</outputDirectory>
		</dependencySet>
	</dependencySets>
	<fileSets>
		<fileSet>
			<!-- 源目錄,此處是把編譯出來的class文件都輸出到根目錄下的classes目錄-->
			<directory>${project.build.directory}/classes</directory>
			<outputDirectory>/classes</outputDirectory>
		</fileSet>
		<fileSet>
			<directory>install/daemon</directory>
			<includes>
		        <include>commons-daemon-1.0.15.jar</include>
		    </includes>
			<outputDirectory>/lib</outputDirectory>
		</fileSet>
		<fileSet>
			<!-- 此處是把daemon的腳本文件輸出到根目錄下的bin目錄-->
			<directory>install/daemon/linux</directory>
			<includes>
		        <include>jsw-test.sh</include>
		        <include>set_auto_start.sh</include>
		    </includes>
			<outputDirectory>/bin</outputDirectory>
		</fileSet>
	</fileSets>
</assembly>
複製代碼

程序包(jsw-test-deamon-linux.zip)打出來後,便可放到linux下進行部署,部署過程以下:

[root@localhost opt]# unzip jsw-test-deamon-linux.zip -d jsw-test
[root@localhost opt]# cd jsw-test/bin
[root@localhost bin]# chmod 777 *.sh
[root@localhost bin]# ./jsw-test.sh start
複製代碼

說明:

  • 本示例中放到/opt下,解壓,修改執行權限,執行。(start,stop,restart參數)。
  • 日誌文件按腳本設置的目錄,輸出在/opt/jsw-test/logs,其下查看啓動日誌:jsw-test.err jsw-test.out
  • /opt/jsw-test/classes/logs下查看程序使用logback的輸出。

四、windows下使用commons-daemon

windows下使用commons-daemon安裝服務跟linux下流程上差很少,差異是使用procrun,腳本的編寫。

4.一、下載commons-daemon及procrun

跟linux同樣,到commons-daemon官網下載。

  • 下載commons-daemon主程序(commons-daemon-1.0.15-bin.zip),解壓出commons-daemon-1.0.15.jar,也可使用前面下載的jar包。
  • 下載procrun,官網的procrun頁面只對它的使用進行講解,在哪裏下載即沒有說起,這裏特別提醒一下,須要在這裏下載procrun,下載commons-daemon-1.0.15-bin-windows.zip。解壓出文件以下:
    procrun包解壓

    複製commons-daemon-1.0.15.jar,prunmgr.exe及prunsrv.exe到安裝目錄(見本示例中爲install及install/windows)。

4.二、編寫程序入口類

跟linux下的入口類不一樣,入口類只須要實現start,stop方法,安裝時指定此類,procrun會根據這些方法進啓動、關閉操做。注意:與linux的不一樣,此兩個方法須要帶參數,不然會報找不到start方法錯誤,程序以下:

/** * Windows服務安裝入口類 * * @author mason * */
public class DaemonMainClassForWindows {

	public static void start(String[] args) {
		// 日誌輸出到程序根目錄(classpath)
		MainClass.initWorkDir();
		LogbackFileLogger logger = new LogbackFileLogger();
		logger.logInfo2file();
	}

	public static void stop(String[] args) {
		System.exit(0);
	}
}
複製代碼

4.三、編寫安裝腳本

使用procrun安裝成服務,需寫bat腳本進行安裝(見示例中的install/daemon/windows目錄下的install.bat,uninstall.bat)。主要是設置服務名稱,java路徑,依賴類,入口類,prunsrv路徑,日誌路徑。注意jvm的大小參數請根據實際狀況修改詳細以下: install.bat:

@echo off

rem 設置程序名稱
set SERVICE_EN_NAME=jsw-test
set SERVICE_CH_NAME=jsw測試程序

rem 設置java路徑
set JAVA_HOME=E:\Program Files\Java\jdk1.8.0_51

rem 設置程序依賴及程序入口類
cd..
set BASEDIR=%CD%
set CLASSPATH=%BASEDIR%\classes;%BASEDIR%\lib\*
set MAIN_CLASS=main.DaemonMainClassForWindows

rem 設置prunsrv路徑 
set SRV=%BASEDIR%\bin\prunsrv.exe

rem 設置日誌路徑及日誌文件前綴
set LOGPATH=%BASEDIR%\logs

rem 輸出信息
echo SERVICE_NAME: %SERVICE_EN_NAME%
echo JAVA_HOME: %JAVA_HOME%
echo MAIN_CLASS: %MAIN_CLASS%
echo prunsrv path: %SRV%

rem 設置jvm
if "%JVM%" == "" goto findJvm
if exist "%JVM%" goto foundJvm
:findJvm
set "JVM=%JAVA_HOME%\jre\bin\server\jvm.dll"
if exist "%JVM%" goto foundJvm
echo can not find jvm.dll automatically,
echo please use COMMAND to localation it
echo for example : set "JVM=C:\Program Files\Java\jdk1.8.0_25\jre\bin\server\jvm.dll"
echo then install service
goto end
:foundJvm

rem 安裝
"%SRV%" //IS//%SERVICE_EN_NAME% --DisplayName="%SERVICE_CH_NAME%" "--Classpath=%CLASSPATH%" "--Install=%SRV%" "--JavaHome=%JAVA_HOME%" "--Jvm=%JVM%" --JvmMs=256 --JvmMx=1024 --Startup=auto --JvmOptions=-Djcifs.smb.client.dfs.disabled=false ++JvmOptions=-Djcifs.resolveOrder=DNS "--StartPath=%BASEDIR%" --StartMode=jvm --StartClass=%MAIN_CLASS% --StartMethod=start "--StopPath=%BASEDIR%" --StopMode=jvm --StopClass=%MAIN_CLASS% --StopMethod=stop --LogPath=%LOGPATH% --StdOutput=auto --StdError=auto
  
:end
複製代碼

uninstall.bat:

@echo off
cd..
set BASEDIR=%CD%
set SERVICE_NAME=jsw-test
set "SRV=%BASEDIR%\bin\prunsrv.exe"

%SRV% //DS//%SERVICE_NAME%

:end
複製代碼

通常安裝好服務後,則可在控制面板-管理程序-服務中進行啓動,關閉管理。若須要使用腳本啓動,可以使用prunmgr.exe進行管理,編寫以下:

@echo off
cd..
set BASEDIR=%CD%
set SERVICE_NAME=prunmgr
set MONITOR_PATH=%BASEDIR%\bin\prunmgr.exe
echo start %SERVICE_NAME% 

%MONITOR_PATH% //MR//%SERVICE_NAME%

:end
複製代碼

4.四、程序打包及安裝

使用maven的assembly插件打包,流程可見上一篇,當前示例打windows的zip包,具體配置以下: pom.xml

<execution>
	<id>make-daemon-win-zip</id>
	<phase>package</phase>
	<goals>
		<goal>single</goal>
	</goals>
	<configuration>
		<finalName>jsw-test</finalName>
		<appendAssemblyId>true</appendAssemblyId>
		<outputDirectory>${project.build.directory}</outputDirectory>
		<descriptors>
			<descriptor>src/main/assembly/daemon-win-zip.xml</descriptor>
		</descriptors>
	</configuration>
</execution>
複製代碼

daemon-win-zip.xml

<assembly>
	<id>daemon-win</id>
	<formats>
		<format>zip</format>
	</formats>
	<includeBaseDirectory>false</includeBaseDirectory>
	<dependencySets>
		<dependencySet>
			<useProjectArtifact>false</useProjectArtifact>
			<outputDirectory>/lib</outputDirectory>
		</dependencySet>
	</dependencySets>
	<fileSets>
		<fileSet>
			<!-- 源目錄,此處是把編譯出來的class文件都輸出到根目錄下的classes目錄-->
			<directory>${project.build.directory}/classes</directory>
			<outputDirectory>/classes</outputDirectory>
		</fileSet>
		<fileSet>
			<directory>install/daemon</directory>
			<includes>
		        <include>commons-daemon-1.0.15.jar</include>
		    </includes>
			<outputDirectory>/lib</outputDirectory>
		</fileSet>
		<fileSet>
			<!-- 此處是把daemon文件所有輸出到根目錄下的install目錄-->
			<directory>install/daemon/windows</directory>
			<outputDirectory>/bin</outputDirectory>
		</fileSet>
	</fileSets>
</assembly>
複製代碼

程序包(jsw-test-deamon-win.zip)打出來後,便可放到windows目錄下進行部署,部署過程以下:

  • 解壓jsw-test-deamon-win.zip到jsw-test-deamon-win目錄,打開bin目錄,運行install.bat。注意:運行彈出窗口,運行時間有點長,需等待。
  • 成功安裝後,可在控制面板-管理程序-服務中進行啓動,關閉管理。
  • 日誌文件按腳本設置的目錄,輸出在jsw-test-daemon-win/logs,其下查看啓動日誌:jsw-test-stderr.2016-07-04.log,jsw-test-stdout.2016-07-04.log
  • jsw-test-daemon-win/classes/logs下查看程序使用logback的輸出

五、附件

jsw-test.zip; 密碼: uryd

相關文章
相關標籤/搜索