Wrapper用途

在做完一个项目程序后,有时会有两种需求想法:

  • 在每次机器重启后自动运行程序。
  • 在程序运行过程中如果发生了死锁、内存溢出或程序崩溃等问题时程序能自动重启。

当然。要实现这两种效果的方案有很多。可以在系统引导文件中加入开机运行程序引导,也可以写一个系统监听程序等等。

现在有一个更简单的解决方案。有一个java程序叫Java Service Wrapper。这是用来在windows或unix/linux系统中将java程序包装成系统服务并执行守护进程。

Java Service Wrapper有三个版本。professional/standard/community 前两个版本要收费功能也更多。对我们来说,社区版的已经够用了,(对于死锁重启需要收费版的)。

分析

从软件的名子上就能看出来。这个软件是用来包装的。我们的程序完成以后会有一个main入口。wrapper就是将这个main方法进行包装再提供自己的一个main入口。这样,我们在运行时都是运行的wrapper的程序。它会建立各种监控和服务,在建立完成后再加载运行被包装的方法。等监控到运行的程序出问题了就会进行相应的处理。

文件解释

所需文件(以windows版本为例)

1.从官网 http://wrapper.tanukisoftware.com 上下载wrapper的软件。

java wrapper可以重复使用吗_Java


2.我们只需要几个核心的文件

wrapper.jar 核心文件,位于lib文件夹中

wrapper.exe 因为是在windows系统中运行所以需要。位于bin文件夹中

wrapper.dll 因为是在windows系统中运行所以需要。 位于lib文件夹中

wrapper.conf 核心配置文件,位于src/conf文件夹中。

实现方式

针对不同程序有不同的实现方式:
1.如果你的程序是不间断运行的。则只需要设置配置文件即可。
2.如果你的程序只是在系统启动时运行一次,或不需要连续运行的,则要加入入口包装类。不然,虽然你的程序已经执行成功且退出了(如:在系统启动时检查下环境再给你的提示信息就结束)。但wrapper会认为你的程序不应该结束,会不停的重启你的服务。这时你要加入包装类就没有这个问题了。

示例

创建java测试项目jar包

1.创建简单的java project

java wrapper可以重复使用吗_jar_02


2.创建主类函数。WrapperDemoMain.java

import java.text.SimpleDateFormat;
import java.util.Date;

public class WrapperDemoMain {

	static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	public static void main(String[] args) {
		while (true) {
			try {
				Date date = new Date();
				// 输出信息
				System.out.println("time: " + format.format(date));
				// 为了更好观察 当前线程睡眠一段随机时间
				Thread.sleep((int) Math.random() * 10000 + 5000);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

3.打包当前项目成my_wrapper_demo.jar

java wrapper可以重复使用吗_java wrapper可以重复使用吗_03


java wrapper可以重复使用吗_Java_04


4.配置Wrapper

  • 解压Wrapper后的文件目录如下:
  • 首先将之前打包的my_wrapper_demo.jar包拷贝到lib目录下
  • 在conf文件下创建my_wrapper_demo.conf。创建方式可以将wrapper.conf拷贝一份重命名为my_wrapper_demo.conf
#java.exe所在位置
wrapper.java.command=D:/Program Files (x86)/Java/jre1.8.0_181/bin/java

#日志级别
wrapper.java.command.loglevel=DEBUG

#主类入口
#方式一:使用wrapper自带WrapperSimpleApp的mainClass是固定写法,#wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp
#此时parameter.1配置自己的主程序入口所在类
#parameter.1是自己的主程序入口所在类(从包名开始)
wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp
wrapper.app.parameter.1=com.gm.test.WrapperDemoMain

#方式二:mainclass如果写成自己的入口程序自己的程序需要实现wrapper的WrapperListener接口
#此时parameter.1无需配置,parameter.1=

#依赖的包,第一个是wrapper包,第二个是自己打的包以及程序依赖包
wrapper.java.classpath.1=../lib/wrapper.jar
wrapper.java.classpath.2=../lib/*.jar

#固定写法,依赖的wrapper的包
wrapper.java.library.path.1=../lib

#日志文件位置
wrapper.logfile=../logs/wrapper.log

#服务名称以及描述信息
wrapper.console.title=my_wrapper_demo
wrapper.name=my_wrapper_demo
wrapper.displayname=my_wrapper_demo
wrapper.description=my_wrapper_demo

# Initial Java Heap Size (in MB)
wrapper.java.initmemory=1024

# Maximum Java Heap Size (in MB)
wrapper.java.maxmemory=1024
  • 使用cmd命令行进入wrapper-windows-x86-32-3.5.36\bin下执行 wrapper -c
    …/conf/my_wrapper_demo.conf进行测试配置信息。显示如下则表示正常启动

    wrapper -i
    …/conf/my_wrapper_demo.conf创建系统服务

    启动系统服务


    常用命令

wrapper配置文件详解

#文件编码,每个配置文件起始位置必须指定该文件的编码格式
encoding=UTF-8
 
# 如果包含配置文件出现问题可以使用debug调试模式,去掉一个"#",格式为#include.debug
#include.debug
 
# 包含子配置文件,可以是配置信息也可以是许可信息
include ../conf/wrapper-license.conf
include ../conf/wrapper2.conf
 
# 是否开启许可文件debug模式
wrapper.license.debug=TRUE
 
 
 
# 指定Wrapper语言,默认使用系统语言
wrapper.lang=en_US
 
#指定Wrapper 语言资源位置,如果该文件不存在则默认设置为en_US
wrapper.lang.folder=../lang
 
 
 
# 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
 
 
 
# Java Main class,也就是程序入口  
#该类需要实现WrapperListener 接口并保证WrapperManager 得到初始化(调用WrapperManager.start(WrapperListener listener, String[] args) 方法)。
wrapper.java.mainclass=com.helloworld.hello.HelloWorld
 
 
 
# Java Classpath配置,必须从序号"1"开始,添加新的jar包后序号递增
wrapper.java.classpath.1=../lib/wrapper.jar
wrapper.java.classpath.2=../lib/hello.jar
 
# Java 类库路径 (Wrapper.DLL 或 libwrapper.so 依赖文件的存放位置)
wrapper.java.library.path.1=../lib
 
 
 
# 32/64位选择,true为自动选择
wrapper.java.additional.auto_bits=TRUE
 
# Java附加参数
wrapper.java.additional.1=
 
 
 
# Java Heap 初始化大小(单位:MB)
wrapper.java.initmemory=3
 
# Java Heap 最大值(单位:MB)
wrapper.java.maxmemory=64
 
 
 
# 应用程序参数,也就是main函数的String[] args参数值,序号需从"1"开始,例如:
wrapper.app.parameter.1=g21121
wrapper.app.parameter.2=http://286.iteye.com/
 
 
 
# 是否显示debug日志
wrapper.debug=TRUE
 
# 控制台信息输出格式
wrapper.console.format=PM
 
# 控制台日志级别
wrapper.console.loglevel=INFO
 
# 日志文件位置及名称
wrapper.logfile=../logs/wrapper.log
 
# 日志文件输出格式
wrapper.logfile.format=LPTM
 
# 日志文件日志级别
wrapper.logfile.loglevel=INFO
 
# 限制日志文件大小,0为不限制,参数:k,m,g等
wrapper.logfile.maxsize=10m
 
# 限制最大日志文件数,0为不限制
wrapper.logfile.maxfiles=0
 
# syslog 日志级别
wrapper.syslog.loglevel=NONE
 
 
 
# 允许使用非连续编号的属性,例如:path的序号可以打乱
wrapper.ignore_sequence_gaps=TRUE
 
# 如果pid文件已经存在则不启动程序
wrapper.pidfile.strict=TRUE
 
# 控制台启动时显示的标题
wrapper.console.title=------------Wrapper Console------------
 
 
 
# 检测JVM中的死锁线程(需要标准版Wrapper)
wrapper.check.deadlock=TRUE
#间隔,单位:秒
wrapper.check.deadlock.interval=10
#出现死锁时处理事件
wrapper.check.deadlock.action=RESTART
#信息输出级别,FULL:全部;SIMPLE:精简;NONE:无;
wrapper.check.deadlock.output=FULL
 
 
 
# 内存溢出检测,Wrapper提供了几种不同的匹配机制
wrapper.filter.trigger.999=wrapper.filter.trigger.*java.lang.OutOfMemoryError
wrapper.filter.allow_wildcards.999=TRUE
wrapper.filter.action.999=NONE
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.
 
 
 
# 邮件基本信息设置
wrapper.event.default.email.debug=TRUE
#smtp服务器地址
wrapper.event.default.email.smtp.host=
#smtp服务器端口
wrapper.event.default.email.smtp.port=25
#邮件主题
wrapper.event.default.email.subject=[%WRAPPER_HOSTNAME%:%WRAPPER_NAME%:%WRAPPER_EVENT_NAME%] Event Notification
#发件人地址
wrapper.event.default.email.sender=<Sender email>
#收件人地址
wrapper.event.default.email.recipient=<Recipient email>
# 指定文件内容
wrapper.event.jvm_restart.email.body=The JVM was restarted.\n\nPlease check on its status.\n
 
 
 
# 邮件日志相关配置
wrapper.event.default.email.attach_log=TRUE
wrapper.event.default.email.maillog.lines=50
wrapper.event.default.email.maillog.format=LPTM
wrapper.event.default.email.maillog.loglevel=INFO
 
 
 
# 触发事件,即当以下事件为true时发送邮件
wrapper.event.wrapper_start.email=TRUE
wrapper.event.jvm_prelaunch.email=TRUE
wrapper.event.jvm_start.email=TRUE
wrapper.event.jvm_started.email=TRUE
wrapper.event.jvm_deadlock.email=TRUE
wrapper.event.jvm_stop.email=TRUE
wrapper.event.jvm_stopped.email=TRUE
wrapper.event.jvm_restart.email=TRUE
wrapper.event.jvm_failed_invocation.email=TRUE
wrapper.event.jvm_max_failed_invocations.email=TRUE
wrapper.event.jvm_kill.email=TRUE
wrapper.event.jvm_killed.email=TRUE
wrapper.event.jvm_unexpected_exit.email=TRUE
wrapper.event.wrapper_stop.email=TRUE