1. 介绍
Java Service Wrapper 是为了解决 Java 应用程序在部署和维护时的诸多问题而诞生的。它主要有以下几个功能:
- 将Java应用程序作为守护程序运行:
- Wrapper可以将Java应用程序作为Windows Service安装。Wrapper附带的脚本也可以在UNIX系统上将Java应用程序作为守护进程安装。
- 提高应用程序可靠性:
- Wrapper会监视JVM进程,并在JVM崩溃或挂起时自动重新启动。包装器确定存在问题后,此过程只需几秒钟。还有一种方法可以配置包装器以监视JVM的控制台输出,并通过重新启动或关闭JVM来对某些字符串作出反应。
- 开箱即用的脚本:
- Wrapper通过为不同的平台提供同一组脚本来减轻开发人员的繁琐任务,这些脚本可以直接用于启动和运行由Wrapper控制的任何Java应用程序。
- 按需重启
- Wrapper为Java应用程序提供了一种请求重新启动其自己的JVM的方法。在许多情况下这可能很有用。修改其配置文件后,应用程序可能希望重新启动。或者可能只是需要重新启动应用程序,以避免出现某种内存问题或资源泄漏。可以通过调用WrapperManager.restart()从JVM内部触发JVM重新启动 。
- 灵活的配置
- Wrapper提供了众多的的配置属性,可用于以任何可能的方式从命令行配置JVM 。配置文件 wrapper.conf 还提供了许多属性可以进行配置。
- 简化应用程序安装
- 通过使用Wrapper的标准脚本以及配置文件wrapper.conf中的相对路径, 通常可以创建一个应用程序,该程序不需要复杂安装即可运行。
2. 下载与安装
2.1 下载
Java Service Wrapper 下载地址:https://wrapper.tanukisoftware.com/doc/english/download.jsp
Java Service Wrapper 提供专业版、标准版与社区版三个版本,这里社区版是免费的的另外两个版本是收费的,支持的系统环境也是比较全面的,这里可以根据自己需求下载。这里下载的是 Macosx Universal 64-bit 社区版。
# 下载之后将解压文件查看文件结构
tar -zxvf wrapper-macosx-universal-64-3.5.44.tar.gz
# 查看文件目录树
tree wrapper-macosx-universal-64-3.5.44
wrapper-macosx-universal-64-3.5.44
├── 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.jnilib
│ ├── wrapper.jar # wrapper主程序
│ ├── wrapperdemo.jar # 示例程序
│ └── wrappertest.jar # 测试程序
├── logs
│ └── wrapper.log # 日志文件
└── src
├── bin
│ ├── App.sh.in # 运行程序脚本
│ └── App.shconf.in # shell 脚本配置文件
└── conf
└── wrapper.conf.in # 原始配置
8 directories, 20 files
2.2 测试Wrapper
因为Wrapper 是开箱即用,所以在启动示例程序时不需要进行其他配置,可以启动测试程序看Wrapper是否能够正常启动。
# 进入 bin 目录
hnbiandeMacBook-Pro:wrapper-macosx-universal-64-3.5.44 hnbian$ cd bin/
hnbiandeMacBook-Pro:bin hnbian$ ll
total 2400
-rwxr-xr-x@ 1 hnbian staff 103K 11 2 09:04 testwrapper
-rwxr-xr-x@ 1 hnbian staff 102K 11 2 09:04 demoapp
-rwxr-xr-x@ 1 hnbian staff 989K 11 2 09:48 wrapper
# 启动测试程序
hnbiandeMacBook-Pro:bin hnbian$ ./demoapp start
Starting Wrapper Demo Application...
Waiting for Wrapper Demo Application.......
running: PID:3887
# 查看日志文件
hnbiandeMacBook-Pro:bin hnbian$ cat ../logs/wrapper.log
STATUS | wrapper | 2020/12/01 17:14:35 | --> Wrapper Started as Daemon
STATUS | wrapper | 2020/12/01 17:14:35 | Java Service Wrapper Community Edition 64-bit 3.5.44
STATUS | wrapper | 2020/12/01 17:14:35 | Copyright (C) 1999-2020 Tanuki Software, Ltd. All Rights Reserved.
STATUS | wrapper | 2020/12/01 17:14:35 | http://wrapper.tanukisoftware.com
STATUS | wrapper | 2020/12/01 17:14:35 |
STATUS | wrapper | 2020/12/01 17:14:35 | Launching a JVM...
INFO | jvm 1 | 2020/12/01 17:14:36 | WrapperManager: Initializing...
INFO | jvm 1 | 2020/12/01 17:14:36 | DemoApp: Initializing...
INFO | jvm 1 | 2020/12/01 17:14:36 | wrapperBinS=../bin/wrapper
INFO | jvm 1 | 2020/12/01 17:14:36 | Demo: start()
INFO | jvm 1 | 2020/12/01 17:14:36 | Demo: Showing dialog...
STATUS | wrapper | 2020/12/01 17:14:39 | --> Wrapper Started as Console
STATUS | wrapper | 2020/12/01 17:14:39 | Java Service Wrapper Community Edition 64-bit 3.5.44
STATUS | wrapper | 2020/12/01 17:14:39 | Copyright (C) 1999-2020 Tanuki Software, Ltd. All Rights Reserved.
STATUS | wrapper | 2020/12/01 17:14:39 | http://wrapper.tanukisoftware.com
STATUS | wrapper | 2020/12/01 17:14:39 |
STATUS | wrapper | 2020/12/01 17:14:39 | Launching a JVM...
INFO | jvm 1 | 2020/12/01 17:14:39 | WrapperManager: Initializing...
INFO | jvm 1 | 2020/12/01 17:14:39 | DemoApp: Initializing...
INFO | jvm 1 | 2020/12/01 17:14:39 | wrapperBinS=../bin/wrapper
INFO | jvm 1 | 2020/12/01 17:14:40 | Started and waiting for a command from the Demo Application
# 如果看到下面页面说明启动成功
# 如果没有启动成功到 logs 文件夹下查看日志是否有报错。
hnbiandeMacBook-Pro:bin hnbian$ ./demoapp
Usage: ./demoapp [ console | start | stop | restart | condrestart | status | install | installstart | remove | dump ]
Commands:
console 在当前控制台中启动
start 作为后台程序进程在后台启动。
stop 停止程序,守护进程或者在 console 中启动
restart 重启
condrestart 仅在运行时重启
status 查看当前状态
install 安装为系统服务随系统启动时自启
installstart 作为后台服务启动并安装为系统服务随系统启动时自启
remove 卸载
dump 查看 java thread dump 报告
3. 配置说明
配置文件介绍
pwd
wrapper-macosx-universal-64-3.5.44/conf
# 查看配置文件内容
cat wrapper.conf
# 指定配置文件编码,在配置文件开始位置必须指定配置文件编码
# 使用 wrapper.conf 不要使用 demoapp.conf
encoding=UTF-8
#********************************************************************
# Wrapper License Properties (Ignored by Community Edition)
#********************************************************************
# Professional and Standard Editions of the Wrapper require a valid
# License Key to start. Licenses can be purchased or a trial license
# requested on the following pages:
# http://wrapper.tanukisoftware.com/purchase
# http://wrapper.tanukisoftware.com/trial
# 是否开启 debug 模式,去掉一个“#” 即开启 debug 模式
##include.debug
# 指定程序包含的配置文件,如果配置文件不存在则忽略,不会导致程序错误
#include ../conf/wrapper-license.conf
#include ../conf/wrapper-license-%WRAPPER_HOST_NAME%.conf
# 许可秘钥信息
#wrapper.license.debug=TRUE
#********************************************************************
# Wrapper Localization
#********************************************************************
# 指定wrapper使用的语言。 en_US 或 ja_JP
wrapper.lang=en_US
# 指定语言资源文件的位置
wrapper.lang.folder=../lang
#********************************************************************
# Wrapper Java 配置
#********************************************************************
# Java Application
# 使用系统环境变量中的 JAVA_HOME指定的 Java home 地址
wrapper.java.command=java
# 单独配置 Java 执行环境的 JAVA_HOME 地址
#set.JAVA_HOME=/java/path
#wrapper.java.command=%JAVA_HOME%/bin/java
# 日志级别
wrapper.java.command.loglevel=INFO
# 程序入口,此类必须实现WrapperListener接口,并保证WrapperManager类已初始化
# See the following page for details:
# http://wrapper.tanukisoftware.com/doc/english/integrate.html
wrapper.java.mainclass=org.tanukisoftware.wrapper.test.Main
# Log level for notices about missing Java Classpath entries.
wrapper.java.classpath.missing.loglevel=WARN
# 依赖的包从 1 开始,第三个是我自己的依赖包
wrapper.java.classpath.1=../lib/wrappertest.jar
wrapper.java.classpath.2=../lib/wrapper.jar
wrapper.java.classpath.3=../mylibs
# Java库路径
wrapper.java.library.path.1=../lib
# Java 运行 JVM 是 32 位还是 64 位,自动识别 true
wrapper.java.additional.auto_bits=TRUE
#附加参数即为java命令可选参数,如下所示:
#设置log4J日志配置文件位置
wrapper.java.additional.1=-Dlog4j.configuration=file:../conf/log4j.properties
wrapper.java.additional.2=
# Java Heap 初始化大小(单位:MB)
#wrapper.java.initmemory=3
# Java Heap 最大值(单位:MB)
#wrapper.java.maxmemory=64
# Application parameters. Add parameters as needed starting from 1
# 这个参数指传给主程序的参数入口。从1开始根据需要添加参数
#wrapper.app.parameter.1=
#********************************************************************
# Wrapper 日志相关配置
#********************************************************************
# 打开Wrapper模式
# 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 为禁用,例如 10m
wrapper.logfile.maxsize=0
# 删除旧文件之前允许的最大滚动日志文件数。默认值0表示无限制
wrapper.logfile.maxfiles=0
# 系统日志输出级别
wrapper.syslog.loglevel=NONE
#********************************************************************
# Wrapper 一般属性
#********************************************************************
# 允许使用非连续编号属性
wrapper.ignore_sequence_gaps=TRUE
# 如果pid文件已经存在,则不启动
wrapper.pidfile.strict=TRUE
# Title to use when running as a console
wrapper.console.title=Test Wrapper Sample Application
#********************************************************************
# Wrapper JVM 检查项
#********************************************************************
# 检测JVM中的死锁线程(专业版可用)
wrapper.check.deadlock=TRUE
# 间隔,单位:秒
wrapper.check.deadlock.interval=10
# 出现死锁时处理办法
# DEBUG :记录导致死锁的原因
# DUMP : 启动线程记录 dump 信息
# GC (Since ver. 3.5.7) : FULL GC
# RESTART : 重启
# SHUTDOWN : 停止 JVM 和 Warpper
# USER_ (Professional Edition) :自定义用户的操作,例如发送提醒邮件等,专业版可用
# PAUSE : 设置为 PAUSE 则会暂停正在运行的应用于 JVM
# RESUME : 将在Java应用程序处于暂停状态时恢复它。如果JVM在暂停时没有停止,则可以使用此选项。
# SUCCESS (Since ver. 3.5.5) :告诉 Wrapper 重置内部调用计数器,并将当前JVM调用计数为“成功”
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
# Ignore -verbose:class output to avoid false positives.
wrapper.filter.trigger.1000=[Loaded java.lang.OutOfMemoryError
wrapper.filter.action.1000=NONE
# (Simple match)
wrapper.filter.trigger.1001=java.lang.OutOfMemoryError
# 仅在使用-XX:+PrintClassHistogram时匹配堆栈跟踪中的文本
# 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 Email 通知. (专业版可用)
#********************************************************************
略
#********************************************************************
# Wrapper Windows 服务配置
#********************************************************************
# WARNING - Do not modify any of these properties when an application
# using this configuration file has been installed as a service.
# Please uninstall the service before modifying this section. The
# service can then be reinstalled.
略
4. 使用示例
编写代码与打包的阶段这里就不错演示了,下面把执行的
- 构建文件结构
# 复制下载好的 wrapper 文件,将多余文件删除,剩余文件目录结构如下
.
├── bin
│ ├── testwrapper
│ └── wrapper
| └── App.sh # 从下载好的 wrapper 包下的src/bin 目录下拷贝App.sh.in 到此文件夹,并改名为App.sh
├── conf # 将所需的配置文件拷贝到此文件夹下
│ └── wrapper.conf # 按下文说明修改次配置文件
├── lib # 将程序 jar 以及依赖的 jar 文件拷贝到此文件夹下
│ ├── libwrapper.so
│ ├── wrapper.jar
│ └── wrappertest.jar
└── logs # 日志文件夹
└── wrapper.log # 在此文件内查看程序日志
- 修改配置文件
# 编辑配置文件
vim wrapper.conf
# 配置内容如下
encoding=UTF-8
wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp
# wrapper jar
wrapper.java.classpath.1=../lib/wrapper.jar
# 指定程序所需配置文件,运行时优先读取这里的配置文件
wrapper.java.classpath.2=../conf/test-wrapper-conf/
# 程序运行本身以及依赖的 jar文件
wrapper.java.classpath.3=../lib/*.jar
# 启动程序的主类
wrapper.app.parameter.1=com.hnbian.ApplicationStart
wrapper.name=wrapper-test
# 可以把堆内存加大 默认 3M
wrapper.java.initmemory=512
# 最大堆内存大小 默认 64M
wrapper.java.maxmemory=2048
- 执行程序
- 启动程序
[root@node1 opt]# bin/App.sh start
Starting test-wrapper.sh...
Waiting for test-wrapper.sh.......
running: PID:1743
- 查看日志
[root@node1 opt]# less wrapper.log
STATUS | wrapper | 2020/12/07 12:18:50 | --> Wrapper Started as Daemon
STATUS | wrapper | 2020/12/07 12:18:50 | Java Service Wrapper Community Edition 64-bit 3.5.44
STATUS | wrapper | 2020/12/07 12:18:50 | Copyright (C) 1999-2020 Tanuki Software, Ltd. All Rights Reserved.
STATUS | wrapper | 2020/12/07 12:18:50 | http://wrapper.tanukisoftware.com
STATUS | wrapper | 2020/12/07 12:18:50 |
STATUS | wrapper | 2020/12/07 12:18:51 | Launching a JVM...
INFO | jvm 1 | 2020/12/07 12:18:52 | WrapperManager: Initializing...
INFO | jvm 1 | 2020/12/07 12:18:55 | log4j:WARN No appenders could be found for logger (org.springframework.web.context.support.StandardServletEnvironment).
INFO | jvm 1 | 2020/12/07 12:18:55 | log4j:WARN Please initialize the log4j system properly.
INFO | jvm 1 | 2020/12/07 12:18:55 | log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
INFO | jvm 1 | 2020/12/07 12:18:56 | SLF4J: Class path contains multiple SLF4J bindings.
INFO | jvm 1 | 2020/12/07 12:18:56 | SLF4J: Found binding in [jar:file:/opt/data-create2/lib/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
INFO | jvm 1 | 2020/12/07 12:18:56 | SLF4J: Found binding in [jar:file:/opt/data-create2/lib/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
INFO | jvm 1 | 2020/12/07 12:18:56 | SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
INFO | jvm 1 | 2020/12/07 12:18:56 | SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
INFO | jvm 1 | 2020/12/07 12:18:56 |
INFO | jvm 1 | 2020/12/07 12:18:56 | . ____ _ __ _ _
INFO | jvm 1 | 2020/12/07 12:18:56 | /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
INFO | jvm 1 | 2020/12/07 12:18:56 | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
INFO | jvm 1 | 2020/12/07 12:18:56 | \\/ ___)| |_)| | | | | || (_| | ) ) ) )
INFO | jvm 1 | 2020/12/07 12:18:56 | ' |____| .__|_| |_|_| |_\__, | / / / /
INFO | jvm 1 | 2020/12/07 12:18:56 | =========|_|==============|___/=/_/_/_/
INFO | jvm 1 | 2020/12/07 12:18:56 | :: Spring Boot :: (v2.0.4.RELEASE)
INFO | jvm 1 | 2020/12/07 12:18:56 |
INFO | jvm 1 | 2020/12/07 12:19:09 | 2020-12-07 12:19:09.118 INFO 11758 --- [erSimpleAppMain] o.apache.catalina.core.StandardService : Starting service [Tomcat]
...
INFO | jvm 1 | 2020/12/07 12:19:23 | data.save.type==>...
...
- 关闭程序
[root@node1 opt]# bin/App.sh stop
Stopping test-wrapper.sh...
Stopped test-wrapper.sh.