Java Service Wrapper 將Java程式部署成系統服務
在使用Java開發應用程式時,我們通常會打包成Jar包獨立執行,但是在實際生產環境中,伺服器重啟或出現異常時,程式往往不能重啟或隨伺服器開機啟動,所以我們可以採用Java Service Wrapper工具解決這一問題,Wrapper可以將我們的Java程式包裝成系統服務,這樣就可以隨著系統的執行而自動運行了。本文主要介紹使用Wrapper將Java程式裝成系統服務的方法,以linux系統為例。
1. 下載Wrapper
Wrapper下載地址:http://wrapper.tanukisoftware.com/doc/english/download.jsp
Wrapper幾乎支援所有的系統環境,目前最新版本為3.5.33,下載Linux x86 64bit版本,作者使用的是3.5.32版。
2. Java Service Wrapper目錄結構
解壓後目錄如下圖:
cmd 控制檯下輸入 tree /f 可以檢視wrapper的詳細目錄和檔案結構,顯示目錄結構如下:
│ README_de.txt //說明
│ README_en.txt //說明
│ README_es.txt //說明
│ README_ja.txt //說明
│
├─bin //執行檔案目錄
│ demoapp //示例程式
│ testwrapper //測試程式
│ wrapper //主程式(重要)
│
├─conf //配置檔案目錄
│ demoapp.conf //示例配置檔案
│ wrapper.conf //主配置檔案(重要,檔名可改)
│
├─doc //說明文件目錄
│ index.html //首頁
│ revisions.txt //版本說明
│ wrapper-community-license-1.3.txt //許可協議
│
├─lib //依賴類庫目錄
│ libwrapper.so //wrapper linux檔案(.so:使用者層的動態庫)
│ wrapper.jar //wrapper主程式(重要)
│ wrapperdemo.jar //示例程式
│ wrappertest.jar //測試程式
│
├─logs //日誌目錄
│ wrapper.log //日誌檔案
│
└─src //原始碼目錄
├─bin //執行程式目錄
│ sh.script.in //shell指令碼原始碼(重要)
│
└─conf //配置目錄
wrapper.conf.in //原始配置
3. 包裝Java 應用程式
這裡我們將Wrapper和StreamServer程式進行整合,將程式打包成可執行的Jar包之後按一下步驟操作,在打包時一定要選擇將程式的依賴包以子資料夾的形式打包,這樣才可以在wrapper的配置檔案中正確配置依賴檔案,如下:
3.1 建立目錄結構
StreamServer
├─bin
├─conf
├─lib
├─logs
└─src
複製Java Service Wrapper檔案到應用程式目錄
(1)複製/bin/wrapper到應用的bin目錄;
(2)複製/bin/testwrapper到應用的bin目錄;
(5)複製/src/conf/wrapper.conf.in到應用的conf目錄下;
(6)複製/lib/libwrapper.so到應用的lib目錄;
(7)複製/lib/wrapper.jar到應用的lib目錄;
複製自己的程式Jar包和依賴資料夾到src目錄下;
注:由於本程式使用了自定義的配置檔案config.properties和日誌配置檔案log4j.properties,而程式中配置檔案的引用路徑是/config/config.properties,所以需要將配置檔案config.properties和log4j.properties單獨拷貝出來,複製到src/config目錄下。
3.2 編輯testwrapper檔案
該檔案是應用程式的啟動入口,將檔案重新命名為程式名
#mv testwrapper StreamServer
修改檔案內容
# Application
APP_NAME="StreamServer"
APP_LONG_NAME="StreamServer Application"
# Wrapper
WRAPPER_CMD="./wrapper"
WRAPPER_CONF="../conf/wrapper.conf"
3.3 編輯wrapper.conf.in 檔案
重新命名wrapper.conf.in為wrapper.conf,所有java service wrapper配置項均在此設定,按以下步驟進行設定:
- 檔案編碼及子配置檔案
檔案頭部包含了配置檔案編碼格式,子配置檔案等相關資訊,如下所示:
#檔案編碼,每個配置檔案起始位置必須指定該檔案的編碼格式
encoding=UTF-8
# 如果包含配置檔案出現問題可以使用debug除錯模式,去掉一個"#"
#include.debug
# 包含子配置檔案,可以是配置資訊也可以是許可資訊
include ../conf/wrapper-license.conf
include ../conf/wrapper2.conf
# 是否開啟許可檔案debug模式
wrapper.license.debug=TRUE
- Wrapper 語言設定
通過這兩項的設定可以指定Wrapper 的語言種類,可以在Wrapper 官網下到這些語言包支援,目前不支援中文。
# 指定Wrapper語言,預設使用系統語言
wrapper.lang=en_US
#指定Wrapper 語言資源位置,如果該檔案不存在則預設設定為en_US
wrapper.lang.folder=../lang
- java執行環境設定
本程式使用PATH環境變數配置資訊
# Java 程式配置:
# (1)預設使用PATH環境變數配置資訊則使用下列配置形式
wrapper.java.command=java
# (2)如果想單獨配置執行程式,則可採用此種配置方式
#set.JAVA_HOME=/java/path
#wrapper.java.command=%JAVA_HOME%/bin/java
# java程式日誌級別
wrapper.java.command.loglevel=INFO
- 程式入口
wrapper的主類,可以是org.tanukisoftware.wrapper.WrapperStartStopApp或WrapperSimpleApp
WrapperStartStopApp可以設定應用程式的啟動和關閉入口
# Java Main class,也就是程式入口
#該類需要實現WrapperListener 介面並保證WrapperManager 得到初始化
wrapper.java.mainclass=wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperStartStopApp
- 類庫設定
# Java Classpath配置,必須從序號"1"開始,新增新的jar包後序號遞增
wrapper.java.classpath.1=../lib/wrapper.jar
wrapper.java.classpath.2=../src/StreamServer.jar
wrapper.java.classpath.3=../src/StreamServer_lib/netty-all-4.0.45.Final.jar
wrapper.java.classpath.4=../src/StreamServer_lib/log4j-1.2.17.jar
...
# Java 類庫路徑 (Wrapper.DLL 或 libwrapper.so 依賴檔案的存放位置)
wrapper.java.library.path.1=../lib
- JVM相關配置
# 32/64位選擇,true為自動選擇
wrapper.java.additional.auto_bits=TRUE
# Java附加引數,若有log4j配置檔案,則要新增引數
wrapper.java.additional.1=-Dlog4j.configuration=../src/config/log4j.properties
附加引數即為java命令可選引數,如下所示:
-d32 use a 32-bit data model if available
-d64 use a 64-bit data model if available
-server to select the "server" VM
The default VM is server.
-cp <class search path of directories and zip/jar files>
-classpath <class search path of directories and zip/jar files>
A : separated list of directories, JAR archives,
and ZIP archives to search for class files.
-D<name>=<value>
set a system property
-verbose[:class|gc|jni]
enable verbose output
-version print product version and exit
-version:<value>
require the specified version to run
-showversion print product version and continue
-jre-restrict-search | -jre-no-restrict-search
include/exclude user private JREs in the version search
-? -help print this help message
-X print help on non-standard options
-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
see also, -agentlib:jdwp=help and -agentlib:hprof=help
-agentpath:<pathname>[=<options>]
load native agent library by full pathname
-javaagent:<jarpath>[=<options>]
load Java programming language agent, see java.lang.instrument
-splash:<imagepath>
show splash screen with specified image
記憶體大小設定:
# Java Heap 初始化大小(單位:MB)
wrapper.java.initmemory=3
# Java Heap 最大值(單位:MB)
wrapper.java.maxmemory=64
- 應用程式引數設定:
WrapperStartStopApp的配置形式
# 應用程式引數,序號需從"1"開始
# 程式的主函式所在類入口
wrapper.app.parameter.1=com.stream.server.StreamServer
wrapper.app.parameter.2=1
wrapper.app.parameter.3=true
# 程式的關閉函式所在類入口
wrapper.app.parameter.4=com.stream.server.StreamServer
wrapper.app.parameter.5=true
wrapper.app.parameter.6=1
# 程式的關閉函式
wrapper.app.parameter.7=stop
- Wrapper 日誌配置
# 是否顯示debug日誌
#wrapper.debug=TRUE
# 控制檯資訊輸出格式(格式檢視docs文件)
wrapper.console.format=PM
# 控制檯日誌級別
wrapper.console.loglevel=INFO
# 日誌檔案位置及名稱
wrapper.logfile=../logs/wrapper.log
# 日誌檔案輸出格式 (格式檢視docs文件)
wrapper.logfile.format=LPTM
# 日誌檔案日誌級別
wrapper.logfile.loglevel=INFO
# 限制日誌檔案大小,0為不限制,引數:k,m,g等
wrapper.logfile.maxsize=50m
# 限制最大日誌檔案數,0為不限制
wrapper.logfile.maxfiles=0
# syslog 日誌級別
wrapper.syslog.loglevel=NONE
- Wrapper 基本屬性配置
# 允許使用非連續編號的屬性,例如:path的序號可以打亂
wrapper.ignore_sequence_gaps=TRUE
# 如果pid檔案已經存在則不啟動程式
wrapper.pidfile.strict=TRUE
# 控制檯啟動時顯示的標題
wrapper.console.title[email protected].long.name@
- Wrapper JVM 檢查
# 檢測JVM中的死鎖執行緒(需要標準版Wrapper)
wrapper.check.deadlock=TRUE
#間隔,單位:秒
wrapper.check.deadlock.interval=60
#出現死鎖時處理事件
wrapper.check.deadlock.action=RESTART
#資訊輸出級別,FULL:全部;SIMPLE:精簡;NONE:無;
wrapper.check.deadlock.output=FULL
記憶體溢位檢測
# 記憶體溢位檢測,Wrapper提供了幾種不同的匹配機制
wrapper.filter.trigger.1000=[Loaded java.lang.OutOfMemoryError
wrapper.filter.action.1000=NONE
wrapper.filter.trigger.1001=java.lang.OutOfMemoryError
#wrapper.filter.trigger.1001=Exception in thread "*" java.lang.OutOfMemoryError
#wrapper.filter.allow_wildcards.1001=TRUE
wrapper.filter.action.1001=RESTART
wrapper.filter.message.1001=The JVM has run out of memory.
3.4 完成
修改成功後的資料夾目錄結構如下:
├─bin
│ StreamServer
│ wrapper
│
├─conf
│ wrapper.conf
│
├─lib
│ libwrapper.so
│ wrapper.jar
│
├─logs
└─src
│ StreamServer.jar
│
├─config
│ config.properties
│ log4j.properties
│
└─StreamServer_lib
java_websocket.jar
log4j-1.2.17.jar
log4j-api-2.0-rc1.jar
log4j-core-2.0-rc1.jar
netty-all-4.0.45.Final.jar
slf4j-api-1.7.5.jar
slf4j-log4j12-1.7.5.jar
4. 部署成系統服務
將上面的StreamServer資料夾移動到linux伺服器/opt目錄下
4.1 賦予服務執行許可權
chmod 775 /opt/StreamServer/bin/StreamServer
chmod 775 /opt/StreamServer/bin/wrapper
4.2 讓服務Server開機自動執行
ln -s /opt/StreamServer/bin/StreamServer /etc/init.d/StreamServer
#新增系統服務,此時服務會被在/etc/rc.d/rcN.d中賦予K/S入口了
chkconfig --add StreamServer
4.3 測試
執行命令:service StreamServer start|stop|restart|status
程式執行時,Java Service Wrapper在/opt/StreamServer/logs/目錄下產生wrapper.log日誌
注意:
1)若StreamServer 需要訪問mysql資料庫,則要檢視開機啟動順序是否在mydqld服務之前,若在之前應進行如下操作
刪除服務新增之後/etc/rc2.d,rc3.d,rc4.d,rc5.d中的StreamServer服務啟動命令檔案,將該命令檔案的啟動順序改到mysqld服務之後,S+數字 該數字在mysqld服務之後
刪除地址軟連結使用 rm -rf symbolic_name
ln -s /etc/init.d/StreamServer /etc/rc3.d/S90StreamServer
ln -s /etc/init.d/StreamServer /etc/rc5.d/S90StreamServer
2)執行出現錯誤 /bin/sh^M: bad interpreter:沒有那個檔案或目錄解決
錯誤分析:
因為我在windows下編輯的指令碼,所以有可能有不可見字元。
指令碼檔案是DOS格式的, 即每一行的行尾以\n\r來標識, 其ASCII碼分別是0x0D, 0x0A.
可以有很多種辦法看這個檔案是DOS格式的還是UNIX格式的, 還是MAC格式的
解決方法是使用dos2unix命令轉一下,即輸入: dos2unix 檔名
dos2unix /opt/SocketServer/bin/StreamServer
dos2unix /opt/SocketServer/bin/wrapper
參考:
Java Service Wrapper使用總結
Wrapper配置詳解及高階應用
Java Service Wrapper簡介與使用