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目录结构

解压后目录如下图:
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的配置文件中正确配置依赖文件,如下:
Java程序打包成可执行Jar包

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=@app.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简介与使用

猜你喜欢

转载自blog.csdn.net/my_tiantian/article/details/77747973