Java Service Wrapper将java程序设置为服务

  有时候我们希望我们java写的程序作为服务注册到系统中,Java Service Wrapper(下面简称wrapper)是目前较为流行的将Java程序部署成Windows服务的解决方案, 本文将讨论如何使用wrapper把我们的程序打包成WIN服务! 

主要作用有:

  1.打包服务

  2.设置JVM参数

  3.所有的日志可以输出到指定文件

0.准备需要注册为服务的程序

public class MapTest {
    private static int i;

    public static void main(String[] args) {
        while (true) {
            try {
                System.out.println("访问次数:" + i++);
                HttpUtil.doGet("http://www.cnblogs.com/qlqwjy/");
                Thread.sleep(2 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

上面程序依赖的jar包:

将上面程序也打成包:(使用eclipse打包或者直接Jdk自带的jar打包)

  

1.下载serviceWrapper包

  下载地址:http://qiaoliqiang.cn/fileDown/wrapper-windows-x86-32-3.5.25.zip

下载后是一个压缩包,解压目录如下:

2.开始注册一个简单的服务:

1. 准备一个目录,例如我在桌面建了一个SW目录,并在里面新建如下结构的目录:   接下来全文的%EXAMPLE_HOME%  就是我新建的SW目录名

%EXAMPLE_HOME%
%EXAMPLE_HOME%in
%EXAMPLE_HOME%conf
%EXAMPLE_HOME%lang
%EXAMPLE_HOME%lib
%EXAMPLE_HOME%mylib
%EXAMPLE_HOME%logs

如下:lang目录是存放支持其他语言的语言包,一般用不到

2.   然后将我们下载的wrapper目录下的文件拷贝到我们上面建的目录:

%WRAPPER_HOME%inwrapper.exe -> %EXAMPLE_HOME%inwrapper.exe
%WRAPPER_HOME%libwrapper.jar -> %EXAMPLE_HOME%libwrapper.jar
%WRAPPER_HOME%libwrapper.dll -> %EXAMPLE_HOME%libwrapper.dll
%WRAPPER_HOME%confwrapper.conf -> %EXAMPLE_HOME%confwrapper.conf


将自己程序打成的包以及自己程序依赖的包放到mylib:

3.修改配置文件    %EXAMPLE_HOME%confwrapper.conf

#java.exe所在位置
wrapper.java.command=C:Program FilesJavajdk1.7.0_80injava.exe
#日志级别 wrapper.java.command.loglevel=INFO
#主类入口,第一个mainClass是固定写法,是wrapper自带的,不可以写成自己的,如果写成自己的入口程序自己的程序需要实现wrapper的WrapperListener接口
#parameter.1是自己的主程序入口所在类(从包名开始) wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp wrapper.app.parameter.1=MapTest
#依赖的包,第一个是wrapper包,第二个是自己打的包以及程序依赖包 wrapper.java.classpath.1=../lib/wrapper.jar wrapper.java.classpath.2=../mylib/*.jar
#固定写法,依赖的wrapper的包 wrapper.java.library.path.1=../lib
#日志文件位置 wrapper.logfile=../logs/wrapper.log
#服务名称以及描述信息 wrapper.console.title=Hello World Server wrapper.name=helloworldserver wrapper.displayname=Hello World Server wrapper.description=Hello World Server

注意:

  (1)上面的主类实际是:org.tanukisoftware.wrapper.WrapperSimpleApp,此类实现了WrapperListener接口。所以如果我们用此参数定义自己的主函数需要实现此接口。实现此接口就不用wrapper.app.parameter.1作为函数参数了

  (2)wrapper.app.parameter.1=MapTest  是将Maptest作为参数传入到主函数中,也就是依次作为类WrapperSimpleApp的main(String[] args)函数的参数。源码如下:

  (3)不能一次传多个参数,生效的始终是第一个参数,传第二个参数也不会生效。传第二个参数或者多个参数是作为MapTest的主函数的参数。

package org.tanukisoftware.wrapper;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.tanukisoftware.wrapper.WrapperListener;
import org.tanukisoftware.wrapper.WrapperManager;
import org.tanukisoftware.wrapper.WrapperPrintStream;
import org.tanukisoftware.wrapper.WrapperSystemPropertyUtil;

public class WrapperSimpleApp implements WrapperListener, Runnable {
    private static WrapperPrintStream m_outInfo;
    private static WrapperPrintStream m_outError;
    private static WrapperPrintStream m_outDebug;
    private Method m_mainMethod;
    private String[] m_appArgs;
    private boolean m_mainStarted;
    private boolean m_mainComplete;
    private Integer m_mainExitCode;
    private boolean m_ignoreMainExceptions;
    private boolean m_startComplete;

    protected WrapperSimpleApp(String[] args) {
        if (class$org$tanukisoftware$wrapper$WrapperManager == null) {
            class$org$tanukisoftware$wrapper$WrapperManager = class$("org.tanukisoftware.wrapper.WrapperManager");
        } else {
            Class arg9999 = class$org$tanukisoftware$wrapper$WrapperManager;
        }

        this.m_mainMethod = null;
        m_outInfo = new WrapperPrintStream(System.out, "WrapperSimpleApp: ");
        m_outError = new WrapperPrintStream(System.out, "WrapperSimpleApp Error: ");
        m_outDebug = new WrapperPrintStream(System.out, "WrapperSimpleApp Debug: ");
        if (args.length < 1) {
            this.showUsage();
            WrapperManager.stop(1);
        } else {
            String mainClassString = args[0];
            String mainMethodString = "main";
            String[] ar = args[0].split("/");
            if (ar.length > 1) {
                mainClassString = ar[0];
                mainMethodString = ar[1];
            }

            Class mainClass;
            try {
                mainClass = Class.forName(mainClassString);
            } catch (ClassNotFoundException arg11) {
                m_outError.println(WrapperManager.getRes().getString("Unable to locate the class {0} : {1}",
                        mainClassString, arg11));
                this.showUsage();
                WrapperManager.stop(1);
                return;
            } catch (ExceptionInInitializerError arg12) {
                m_outError.println(WrapperManager.getRes()
                        .getString("Class {0} found but could not be initialized due to:", mainClassString));
                arg12.printStackTrace(m_outError);
                WrapperManager.stop(1);
                return;
            } catch (LinkageError arg13) {
                m_outError.println(WrapperManager.getRes()
                        .getString("Class {0} found but could not be initialized: {1}", mainClassString, arg13));
                WrapperManager.stop(1);
                return;
            }

            try {
                this.m_mainMethod = mainClass.getMethod(mainMethodString, new Class[]{String[].class});
            } catch (NoSuchMethodException arg9) {
                try {
                    this.m_mainMethod = mainClass.getMethod(mainMethodString, new Class[0]);
                } catch (NoSuchMethodException arg8) {
                    ;
                }

                if (this.m_mainMethod == null) {
                    m_outError.println(WrapperManager.getRes().getString(
                            "Unable to locate a public static {2} method in class {0} : {1}", mainClassString, arg9,
                            mainMethodString));
                    this.showUsage();
                    WrapperManager.stop(1);
                    return;
                }
            } catch (SecurityException arg10) {
                m_outError.println(WrapperManager.getRes().getString(
                        "Unable to locate a public static {2} method in class {0} : {1}", mainClassString, arg10,
                        mainMethodString));
                this.showUsage();
                WrapperManager.stop(1);
                return;
            }

            int modifiers = this.m_mainMethod.getModifiers();
            if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)) {
                String[] appArgs = new String[args.length - 1];
                System.arraycopy(args, 1, appArgs, 0, appArgs.length);
                WrapperManager.start(this, appArgs);
            } else {
                m_outError.println(WrapperManager.getRes().getString(
                        "The {1} method in class {0} must be declared public and static.", mainClassString,
                        mainMethodString));
                this.showUsage();
                WrapperManager.stop(1);
            }
        }
    }

    public void run() {
        synchronized (this) {
            this.m_mainStarted = true;
            this.notifyAll();
        }

        Object t = null;

        try {
            if (WrapperManager.isDebugEnabled()) {
                m_outDebug.println(WrapperManager.getRes().getString("invoking main method"));
            }

            try {
                this.m_mainMethod.invoke((Object) null, new Object[]{this.m_appArgs});
            } catch (IllegalArgumentException arg15) {
                this.m_mainMethod.invoke((Object) null, new Object[0]);
            } finally {
                Thread.currentThread().setPriority(10);
            }

            if (WrapperManager.isDebugEnabled()) {
                m_outDebug.println(WrapperManager.getRes().getString("main method completed"));
            }

            synchronized (this) {
                this.m_mainComplete = true;
                this.notifyAll();
                return;
            }
        } catch (IllegalAccessException arg18) {
            t = arg18;
        } catch (IllegalArgumentException arg19) {
            t = arg19;
        } catch (InvocationTargetException arg20) {
            t = arg20.getTargetException();
            if (t == null) {
                t = arg20;
            }
        }

        m_outInfo.println();
        m_outError.println(WrapperManager.getRes().getString("Encountered an error running main:"));
        ((Throwable) t).printStackTrace(m_outError);
        synchronized (this) {
            if (this.m_ignoreMainExceptions) {
                if (!this.m_startComplete) {
                    this.m_mainComplete = true;
                    this.notifyAll();
                }

            } else if (this.m_startComplete) {
                WrapperManager.stop(1);
            } else {
                this.m_mainComplete = true;
                this.m_mainExitCode = new Integer(1);
                this.notifyAll();
            }
        }
    }

    public Integer start(String[] args) {
        boolean waitForStartMain = WrapperSystemPropertyUtil
                .getBooleanProperty(WrapperSimpleApp.class.getName() + ".waitForStartMain", false);
        this.m_ignoreMainExceptions = WrapperSystemPropertyUtil
                .getBooleanProperty(WrapperSimpleApp.class.getName() + ".ignoreMainExceptions", false);
        int maxStartMainWait = WrapperSystemPropertyUtil
                .getIntProperty(WrapperSimpleApp.class.getName() + ".maxStartMainWait", 2);
        maxStartMainWait = Math.max(1, maxStartMainWait);
        int maxLoops;
        if (waitForStartMain) {
            maxLoops = Integer.MAX_VALUE;
            if (WrapperManager.isDebugEnabled()) {
                m_outDebug.println(WrapperManager.getRes()
                        .getString("start(args) Will wait indefinitely for the main method to complete."));
            }
        } else {
            maxLoops = maxStartMainWait;
            if (WrapperManager.isDebugEnabled()) {
                m_outDebug.println(WrapperManager.getRes().getString(
                        "start(args) Will wait up to {0} seconds for the main method to complete.",
                        new Integer(maxStartMainWait)));
            }
        }

        Thread mainThread = new Thread(this, "WrapperSimpleAppMain");
        synchronized (this) {
            this.m_appArgs = args;
            mainThread.start();
            Thread.currentThread().setPriority(10);

            while (!this.m_mainStarted) {
                try {
                    this.wait(1000L);
                } catch (InterruptedException arg10) {
                    ;
                }
            }

            for (int loops = 0; loops < maxLoops && !this.m_mainComplete; ++loops) {
                try {
                    this.wait(1000L);
                } catch (InterruptedException arg9) {
                    ;
                }

                if (!this.m_mainComplete) {
                    WrapperManager.signalStarting(5000);
                }
            }

            this.m_startComplete = true;
            if (WrapperManager.isDebugEnabled()) {
                m_outDebug
                        .println(WrapperManager.getRes().getString("start(args) end.  Main Completed={0}, exitCode={1}",
                                new Boolean(this.m_mainComplete), this.m_mainExitCode));
            }

            return this.m_mainExitCode;
        }
    }

    public int stop(int exitCode) {
        if (WrapperManager.isDebugEnabled()) {
            m_outDebug.println(WrapperManager.getRes().getString("stop({0})", new Integer(exitCode)));
        }

        return exitCode;
    }

    public void controlEvent(int event) {
        if (event != 202 || !WrapperManager.isLaunchedAsService() && !WrapperManager.isIgnoreUserLogoffs()) {
            if (WrapperManager.isDebugEnabled()) {
                m_outDebug.println(WrapperManager.getRes().getString("controlEvent({0}) Stopping", new Integer(event)));
            }

            WrapperManager.stop(0);
        } else {
            m_outInfo.println(WrapperManager.getRes().getString("User logged out.  Ignored."));
        }

    }

    protected void showUsage() {
        System.out.println();
        System.out.println(WrapperManager.getRes().getString("WrapperSimpleApp Usage:"));
        System.out.println(WrapperManager.getRes().getString(
                "  java org.tanukisoftware.wrapper.WrapperSimpleApp {app_class{/app_method}} [app_arguments]"));
        System.out.println();
        System.out.println(WrapperManager.getRes().getString("Where:"));
        System.out.println(WrapperManager.getRes()
                .getString("  app_class:      The fully qualified class name of the application to run."));
        System.out.println(WrapperManager.getRes()
                .getString("  app_arguments:  The arguments that would normally be passed to the"));
        System.out.println(WrapperManager.getRes().getString("                  application."));
    }

    public static void main(String[] args) {
        new WrapperSimpleApp(args);
    }
}
 

4.开始注册服务以及测试 

(1)控制台测试

C:UsersAdministrator>cd C:UsersAdministratorDesktopSW

C:UsersAdministratorDesktopSW>binwrapper.exe -c ..confwrapper.conf
wrapper  | --> Wrapper Started as Console
wrapper  | Java Service Wrapper Community Edition 32-bit 3.5.25
wrapper  |   Copyright (C) 1999-2014 Tanuki Software, Ltd. All Rights Reserved.
wrapper  |     http://wrapper.tanukisoftware.com
wrapper  |
wrapper  | Launching a JVM...
wrapper  | Java Command Line:
wrapper  |   Command: "C:Program FilesJavajdk1.7.0_80injava.exe" -Djava.library.path="../lib" -classpath "../lib/wrapper.jar;../mylib/commons-logging-1.0.4.jar;../mylib/commons.jar;../mylib/httpclient-4.3.1.jar;../mylib/httpcore-4.3.jar;../mylib/httpmime-4.3.1.jar;../mylib/log4j-1.2.12.jar" -Dwrapper.key="2azws1iyaXYR9r26" -Dwrapper.port=32000 -Dwrapper.jvm.port.min=31000 -Dwrapper.jvm.port.max=31999 -Dwrapper.pid=21292 -Dwrapper.version="3.5.25" -Dwrapper.native_library="wrapper" -Dwrapper.arch="x86" -Dwrapper.cpu.timeout="10" -Dwrapper.jvmid=1 org.tanukisoftware.wrapper.WrapperSimpleApp MapTest
jvm 1    | WrapperManager: Initializing...
jvm 1    | WrapperManager:
jvm 1    | WrapperManager: WARNING - Unable to load the Wrapper''s native library 'wrapper.dll'.
jvm 1    | WrapperManager:           The file is located on the path at the following location but
jvm 1    | WrapperManager:           could not be loaded:
jvm 1    | WrapperManager:             C:UsersAdministratorDesktopSWin..libwrapper.dll
jvm 1    | WrapperManager:           Please verify that the file is both readable and executable by the
jvm 1    | WrapperManager:           current user and that the file has not been corrupted in any way.
jvm 1    | WrapperManager:           One common cause of this problem is running a 32-bit version
jvm 1    | WrapperManager:           of the Wrapper with a 64-bit version of Java, or vica versa.
jvm 1    | WrapperManager:           This is a 64-bit JVM.
jvm 1    | WrapperManager:           Reported cause:
jvm 1    | WrapperManager:             C:UsersAdministratorDesktopSWlibwrapper.dll: Can't load IA 32-bit .dll on a AMD 64-bit platform
jvm 1    | WrapperManager:           System signals will not be handled correctly.
jvm 1    | WrapperManager:
jvm 1    | 访问次数:0
jvm 1    | log4j:WARN No appenders could be found for logger (org.apache.http.impl.conn.BasicClientConnectionManager).
jvm 1    | log4j:WARN Please initialize the log4j system properly.
jvm 1    | 访问次数:1
jvm 1    | 访问次数:2
jvm 1    | 访问次数:3

(2)将程序注册为服务:

binwrapper.exe -i ..confwrapper.conf

结果:

wrapper  | Hello World Server service installed.

(3)启动服务:

net start helloworld

 或者:

binwrapper.exe -t ..confwrapper.conf

启动之后我们回看到程序输出在logswrapper.log文件内:

(4)停止服务

net stop helloword

或者

binwrapper.exe -p ..confwrapper.conf

(5)删除服务

sc delete helloword

或者

binwrapper.exe -r ..confwrapper.conf

-----------上面是在系统有Java环境的情况下的设置,现在假设我们不存在Java运行环境,也就是没有JRE与JDK:-------------

(1)拷贝java安装目录下的JRE(包含bin目录和相关lib)目录到上面的目录%EXAMPLE_HOME%,如下:

jre目录下:

(2)修改配置文件,利用我们上面的jre目录下的jar包和binjava.exe

#java.exe所在位置
wrapper.java.command=../jre/bin/java.exe
#日志级别
wrapper.java.command.loglevel=INFO

#主类入口,第一个mainClass是固定写法,是wrapper自带的,不可以写成自己的,如果写成自己的入口程序自己的程序需要实现wrapper的WrapperListener接口
wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp
#parameter.1是自己的主程序入口所在类(从包名开始)
wrapper.app.parameter.1=MapTest

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


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

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

#服务名称以及描述信息
wrapper.console.title=Hello World Server
wrapper.name=helloworldserver
wrapper.displayname=Hello World Server
wrapper.description=Hello World Server

(3)安装服务与测试与上面一样:


C:UsersliqiangDesktopxxxSW>binwrapper.exe -c ..confwrapper.conf
wrapper  | --> Wrapper Started as Console
wrapper  | Java Service Wrapper Community Edition 32-bit 3.5.25
wrapper  |   Copyright (C) 1999-2014 Tanuki Software, Ltd. All Rights Reserved.
wrapper  |     http://wrapper.tanukisoftware.com
wrapper  |
wrapper  | Launching a JVM...
wrapper  | Java Command Line:
wrapper  |   Command: "..jreinjava.exe" -Djava.library.path="../lib" -classp
arsets.jar;../jre/lib/deploy.jar;../jre/lib/javaws.jar;../jre/lib/jce.jar;../jre
/lib/jsse.jar;../jre/lib/management-agent.jar;../jre/lib/plugin.jar;../jre/lib/r
apper.jar;../mylib/commons-logging-1.0.4.jar;../mylib/commons.jar;../mylib/httpc
r;../mylib/httpmime-4.3.1.jar;../mylib/log4j-1.2.12.jar" -Dwrapper.key="408rjGp1
.jvm.port.min=31000 -Dwrapper.jvm.port.max=31999 -Dwrapper.pid=336144 -Dwrapper.
y="wrapper" -Dwrapper.arch="x86" -Dwrapper.cpu.timeout="10" -Dwrapper.jvmid=1 or
p MapTest
jvm 1    | WrapperManager: Initializing...
jvm 1    | WrapperManager:
jvm 1    | WrapperManager: WARNING - Unable to load the Wrapper''s native librar
jvm 1    | WrapperManager:           The file is located on the path at the foll
jvm 1    | WrapperManager:           could not be loaded:
jvm 1    | WrapperManager:             C:UsersliqiangDesktopxxxSWin..li
jvm 1    | WrapperManager:           Please verify that the file is both readabl
jvm 1    | WrapperManager:           current user and that the file has not been
jvm 1    | WrapperManager:           One common cause of this problem is running
jvm 1    | WrapperManager:           of the Wrapper with a 64-bit version of Jav
jvm 1    | WrapperManager:           This is a 64-bit JVM.
jvm 1    | WrapperManager:           Reported cause:
jvm 1    | WrapperManager:             C:UsersliqiangDesktopxxxSWlibwrapp
MD 64-bit platform
jvm 1    | WrapperManager:           System signals will not be handled correctl
jvm 1    | WrapperManager:
jvm 1    | 访问次数:0
jvm 1    | log4j:WARN No appenders could be found for logger (org.apache.http.im
jvm 1    | log4j:WARN Please initialize the log4j system properly.
jvm 1    | 访问次数:1
wrapper  | CTRL-C trapped.  Shutting down.
wrapper  | <-- Wrapper Stopped

C:UsersliqiangDesktopxxxSW>binwrapper.exe -i ..confwrapper.conf
wrapperm | Hello World Server service installed.

C:UsersliqiangDesktopxxxSW>java
'java' 不是内部或外部命令,也不是可运行的程序
或批处理文件。

C:UsersliqiangDesktopxxxSW>javac
'javac' 不是内部或外部命令,也不是可运行的程序
或批处理文件。

  为了验证我们的服务是使用的jre目录下的JDK,我们可以将jre目录删掉进行测试,或者是将配置文件中jrelib的引入注释掉进行测试。

  现在我们将jre目录删掉,启动服务报错如下:

  在wrapper.log中查看到的日志文件如下:

 

  至此我们实现了简单的有JRE与无JRE两种情况的注册服务,实际没有JRE环境的时候我们只需要将我们的JRE附到目录中并且在wrapper.conf中指明所在路径即可。

补充1.:上面配置会导致JVM不断重启,需要加JVM参数以及设置,同时设置服务开机启动:并且使用一变量记住我们的项目路径;修改wrapper.conf并且删掉服务重新添加:

#定义了一个根路径,注意set和.之间没有空格,下面就可以用%basePath%取此变量
set.basePath=C:UsersliqiangDesktopxxxSW

#java.exe所在位置
wrapper.java.command=%basePath%/jre/bin/java.exe
#日志级别
wrapper.java.command.loglevel=INFO

#主类入口,第一个mainClass是固定写法,是wrapper自带的,不可以写成自己的,如果写成自己的入口程序自己的程序需要实现wrapper的WrapperListener接口
wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp
#parameter.1是自己的主程序入口所在类(从包名开始)
wrapper.app.parameter.1=MapTest

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


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

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

#服务名称以及描述信息
wrapper.console.title=Hello World Server
wrapper.name=helloworldserver
wrapper.displayname=Hello World Server
wrapper.description=Hello World Server

wrapper.jmx=false
wrapper.on_exit.0=SHUTDOWN
wrapper.on_exit.default=RESTART

wrapper.ntservice.interactive = true
#服务开机启动
wrapper.ntservice.starttype=AUTO_START
wrapper.tray = true

wrapper.java.monitor.deadlock = true
wrapper.java.monitor.heap = true
wrapper.java.monitor.gc.restart = true


# Java Heap 初始化大小(单位:MB)
wrapper.java.initmemory=128
# Java Heap 最大值(单位:MB)
wrapper.java.maxmemory=128

删除重装服务:

C:UsersliqiangDesktopxxxSW>binwrapper.exe -r ..confwrapper.conf
wrapperm | Hello World Server service removed.
C:UsersliqiangDesktopxxxSW>binwrapper.exe -c ..confwrapper.conf
wrapper  | --> Wrapper Started as Console
wrapper  | Java Service Wrapper Community Edition 32-bit 3.5.25
wrapper  |   Copyright (C) 1999-2014 Tanuki Software, Ltd. All Rights Reserved.
wrapper  |     http://wrapper.tanukisoftware.com
wrapper  |
wrapper  | Launching a JVM...
wrapper  | Java Command Line:
wrapper  |   Command: "C:UsersliqiangDesktopxxxSWjreinjava.exe" -Xms128
-classpath "../jre/lib/alt-rt.jar;../jre/lib/charsets.jar;../jre/lib/deploy.jar;
;../jre/lib/jfr.jar;../jre/lib/jfxrt.jar;../jre/lib/jsse.jar;../jre/lib/manageme
e/lib/resources.jar;../jre/lib/rt.jar;../lib/wrapper.jar;../mylib/commons-loggin
b/httpclient-4.3.1.jar;../mylib/httpcore-4.3.jar;../mylib/httpmime-4.3.1.jar;../
P7sqJIaMu25Avke" -Dwrapper.port=32000 -Dwrapper.jvm.port.min=31000 -Dwrapper.jvm
rapper.version="3.5.25" -Dwrapper.native_library="wrapper" -Dwrapper.arch="x86"
id=1 org.tanukisoftware.wrapper.WrapperSimpleApp MapTest
jvm 1    | WrapperManager: Initializing...
jvm 1    | WrapperManager:
jvm 1    | WrapperManager: WARNING - Unable to load the Wrapper''s native librar
jvm 1    | WrapperManager:           The file is located on the path at the foll
jvm 1    | WrapperManager:           could not be loaded:
jvm 1    | WrapperManager:             C:UsersliqiangDesktopxxxSWin..li
jvm 1    | WrapperManager:           Please verify that the file is both readabl
jvm 1    | WrapperManager:           current user and that the file has not been
jvm 1    | WrapperManager:           One common cause of this problem is running
jvm 1    | WrapperManager:           of the Wrapper with a 64-bit version of Jav
jvm 1    | WrapperManager:           This is a 64-bit JVM.
jvm 1    | WrapperManager:           Reported cause:
jvm 1    | WrapperManager:             C:UsersliqiangDesktopxxxSWlibwrapp
MD 64-bit platform
jvm 1    | WrapperManager:           System signals will not be handled correctl
jvm 1    | WrapperManager:
jvm 1    | 访问次数:0
wrapper  | CTRL-C trapped.  Shutting down.
jvm 1    | log4j:WARN No appenders could be found for logger (org.apache.http.im
jvm 1    | log4j:WARN Please initialize the log4j system properly.
wrapper  | <-- Wrapper Stopped

C:UsersliqiangDesktopxxxSW>binwrapper.exe -i ..confwrapper.conf
wrapperm | Hello World Server service installed.

如果我们想检测JVM参数可以用jps+jmap监测即可:

C:Usersliqiang>jps
505668 Jps
504320 WrapperSimpleApp
487768

C:Usersliqiang>jmap -heap 504320
Attaching to process ID 504320, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.80-b11

using thread-local object allocation.
Parallel GC with 4 thread(s)

Heap Configuration:
   MinHeapFreeRatio = 0
   MaxHeapFreeRatio = 100
   MaxHeapSize      = 134217728 (128.0MB)
   NewSize          = 1310720 (1.25MB)
   MaxNewSize       = 17592186044415 MB
   OldSize          = 5439488 (5.1875MB)
   NewRatio         = 2
   SurvivorRatio    = 8
   PermSize         = 21757952 (20.75MB)
   MaxPermSize      = 85983232 (82.0MB)
   G1HeapRegionSize = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 34603008 (33.0MB)
   used     = 9710016 (9.26019287109375MB)
   free     = 24892992 (23.73980712890625MB)
   28.06119051846591% used
From Space:
   capacity = 5242880 (5.0MB)
   used     = 0 (0.0MB)
   free     = 5242880 (5.0MB)
   0.0% used
To Space:
   capacity = 5242880 (5.0MB)
   used     = 0 (0.0MB)
   free     = 5242880 (5.0MB)
   0.0% used
PS Old Generation
   capacity = 89653248 (85.5MB)
   used     = 0 (0.0MB)
   free     = 89653248 (85.5MB)
   0.0% used
PS Perm Generation
   capacity = 22020096 (21.0MB)
   used     = 6630336 (6.32318115234375MB)
   free     = 15389760 (14.67681884765625MB)
   30.110386439732142% used

3336 interned Strings occupying 269976 bytes.

补充2:我们可以用上面的service wrapper的bin包中的bat文件进行安装服务: (将上面安下载解压后的wrapper-windows-x86-32-3.5.25in中的文件复制到我们的%EXAMPLE_HOME%in目录下)

  我们只需要点击上面的bat文件即可实现上面的操作。

*************************

我已经将我的一个例子上传到我的服务器,下载地址:http://qiaoliqiang.cn/fileDown/serviceWrapperExample.zip

下载解压之后只需要将自己程序打的包以及依赖包放到mylib目录下,修改confwrapper.conf文件中下面两处

set.basePath=C:UsersliqiangDesktopxxxSW   #替换为自己的目录
#parameter.1是自己的主程序入口所在类(从包名开始)
wrapper.app.parameter.1=MapTest   #替换为自己的程序入口

然后点击bin目录的TestWrapper.bat测试即可

**************************

3.将log4j日志与servicewrapper日志进行整合

开发环境下一切正常。用JavaServiceWrapper部署到服务器上之后,发现log文件没有生成。同时在wrapper的log中有两行log4j的错误信息:

     log4j:WARN No appenders could be found for logger (com.xxxxx).

     log4j:WARN Please initialize the log4j system properly.

查找了一番,最后发现在wrapper.conf中加入一行,硬性指明log4j的配置文件就OK了:

 wrapper.java.additional.1=-Dlog4j.configuration=file:../conf/log4j.properties

StackOverflow上有人回答类似的问题,用的方法是

     wrapper.java.additional.1=-Dlog4j.configuration=../config/log4j.properties

但是我这样测试没成功。不知道是不是和版本有关。

(1) 测试代码:

package serviceWrapper;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MapTest {
    private static Logger log = LoggerFactory.getLogger(MapTest.class);

    public static void main(String[] args) {
        int times = 0;
        while (true) {
            try {
                Thread.sleep(3 * 1000);
            } catch (InterruptedException e) {
            }
            try {
                int i = 1 / 0;
            } catch (Exception e) {
                log.error("error[{}] by / 0 ", times++, e);
            }
        }
    }

}

(2)测试代码打成包并一起复制到mylib目录下:

依赖的jar包以及自己打的包:

 (3)目录结构:

 (4)bin目录与上面一样,jre也一样,lang也一样,lib也一样,logs也一样,mylib在(2)中换过,将log4j.properties文件复制到conf目录下:

log4j.properties文件:

log4j.rootLogger=info,A,B

log4j.appender.A=org.apache.log4j.ConsoleAppender
log4j.appender.A.layout=org.apache.log4j.PatternLayout
log4j.appender.A.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n

log4j.appender.B=org.apache.log4j.RollingFileAppender
log4j.appender.B.File=E:\test.log
log4j.appender.B.MaxFileSize=10MB
log4j.appender.B.MaxBackupIndex=5
log4j.appender.B.layout=org.apache.log4j.PatternLayout
log4j.appender.B.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n

(5)修改wrapper.conf文件:

#定义了一个根路径,注意set和.之间没有空格,下面就可以用%basePath%取此变量
set.basePath=C:UsersliqiangDesktoplogTest

#java.exe所在位置
wrapper.java.command=%basePath%/jre/bin/java.exe

#主类入口,第一个mainClass是固定写法,是wrapper自带的,不可以写成自己的,如果写成自己的入口程序自己的程序需要实现wrapper的WrapperListener接口
wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp
#parameter.1是自己的主程序入口所在类(从包名开始),生效的始终是第一个参数
wrapper.app.parameter.1=serviceWrapper.MapTest
wrapper.app.parameter.2=MapTest

# Java Classpath配置,必须从序号"1"开始,添加新的jar包后序号递增
#JRE的包
wrapper.java.classpath.1=../jre/lib/*.jar
#wrapper.jar
wrapper.java.classpath.2=../lib/wrapper.jar
#自己的包以及程序依赖包
wrapper.java.classpath.3=../mylib/*.jar

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

#日志文件位置
wrapper.logfile=../logs/wrapper.log
# 控制台信息输出格式
wrapper.console.format=PM
# 日志文件输出格式
wrapper.logfile.format=LPTM
# 日志文件日志级别
wrapper.logfile.loglevel=INFO

#服务名称以及描述信息
wrapper.console.title=Hello World Server
wrapper.name=helloworldserver
wrapper.displayname=Hello World Server
wrapper.description=Hello World Server

wrapper.jmx=false
wrapper.on_exit.0=SHUTDOWN
wrapper.on_exit.default=RESTART

wrapper.ntservice.interactive = true
#服务开机启动
wrapper.ntservice.starttype=AUTO_START
wrapper.tray = true


wrapper.java.monitor.deadlock = true
wrapper.java.monitor.heap = true
wrapper.java.monitor.gc.restart = true


# Java Heap 初始化大小(单位:MB)
wrapper.java.initmemory=128
# Java Heap 最大值(单位:MB)
wrapper.java.maxmemory=128

# 32/64位选择,true为自动选择
wrapper.java.additional.auto_bits=TRUE

#附加参数即为java命令可选参数,如下所示:
#设置log4J日志文件位置
wrapper.java.additional.1=-Dlog4j.configuration=file:../conf/log4j.properties

注意:  附加参数 wrapper.java.additional.1 即为java命令可选参数(可用于指定JVM参数与指定垃圾收集器组合),如下所示:

C:Usersliqiang>java
用法: java [-options] class [args...]
           (执行类)
   或  java [-options] -jar jarfile [args...]
           (执行 jar 文件)
其中选项包括:
    -d32          使用 32 位数据模型 (如果可用)
    -d64          使用 64 位数据模型 (如果可用)
    -server       选择 "server" VM
    -hotspot      是 "server" VM 的同义词 [已过时]
                  默认 VM 是 server.

    -cp <目录和 zip/jar 文件的类搜索路径>
    -classpath <目录和 zip/jar 文件的类搜索路径>
                  用 ; 分隔的目录, JAR 档案
                  和 ZIP 档案列表, 用于搜索类文件。
    -D<名称>=<值>
                  设置系统属性
    -verbose:[class|gc|jni]
                  启用详细输出
    -version      输出产品版本并退出
    -version:<值>
                  需要指定的版本才能运行
    -showversion  输出产品版本并继续
    -jre-restrict-search | -no-jre-restrict-search
                  在版本搜索中包括/排除用户专用 JRE
    -? -help      输出此帮助消息
    -X            输出非标准选项的帮助
    -ea[:<packagename>...|:<classname>]
    -enableassertions[:<packagename>...|:<classname>]
                  按指定的粒度启用断言
    -da[:<packagename>...|:<classname>]
    -disableassertions[:<packagename>...|:<classname>]
                  禁用具有指定粒度的断言
    -esa | -enablesystemassertions
                  启用系统断言
    -dsa | -disablesystemassertions
                  禁用系统断言
    -agentlib:<libname>[=<选项>]
                  加载本机代理库 <libname>, 例如 -agentlib:hprof
                  另请参阅 -agentlib:jdwp=help 和 -agentlib:hprof=help
    -agentpath:<pathname>[=<选项>]
                  按完整路径名加载本机代理库
    -javaagent:<jarpath>[=<选项>]
                  加载 Java 编程语言代理, 请参阅 java.lang.instrument
    -splash:<imagepath>
                  使用指定的图像显示启动屏幕
有关详细信息, 请参阅 http://www.oracle.com/technetwork/java/javase/documentation

(6)点击bin目录下的TestWrapper.bat测试控制台:

logswrapper.log文件内容如下:

E: est.log文件内容如下:

 

  log4j生成的日志文件与wrapper.logs文件的内容几乎一样,只是格式不一样。

   至此完成与log4j的整合,其实与log4j整合也简单,就是在配置文件下面加一行引入log4j.properties文件的位置

wrapper.java.additional.1=-Dlog4j.configuration=file:../conf/log4j.properties

4.将tomcat注册为服务:设置tomcat服务开机启动,还是在没有JRE的环境下进行:(公司集成部署系统可以采用这种方式)

1.新建一目录,解压一个全新的tomcat,在%TOMCAT%目录下新建一个servicewrapper目录:

2.将自己的项目解压之后放在webapps目录下(这里采用目录解压部署,参考:https://www.cnblogs.com/qlqwjy/p/9478649.html)

3.与上面部署一样将所需要的文件拷贝到servicewrapper目录下:

 

  bin目录是启动服务的bat文件和wrapper.exe文件,conf是wrapper.conf文件,jre是拷贝的jre环境,lang是空目录,lib是wrapper.jar和wrapper.dll文件,logs用于存放wrapper.log文件,mylib可以存放自己以及第三方jar包(不过web项目用不到这个)。

4.修改wrapper.conf文件的配置:(重要)

#定义了一个根路径,注意set和.之间没有空格,下面就可以用%basePath%取此变量
set.basePath=C:UsersliqiangDesktop
2	omcatapache-tomcat-7.0.72

#java.exe所在位置
wrapper.java.command=%basePath%/servicewrapper/jre/bin/java.exe
#日志级别
wrapper.java.command.loglevel=INFO

#依赖的包,第一个是wrapper包,第二个是自己打的包以及程序依赖包
#jre的lb路径
wrapper.java.classpath.1=%basePath%/servicewrapper/jre/lib/*.jar
#wrapper.jar路径
wrapper.java.classpath.2=%basePath%/servicewrapper/lib/wrapper.jar
#自己的依赖jar包
wrapper.java.classpath.3=%basePath%/servicewrapper/mylib/*.jar
#tomcat依赖的包(tomcat启动类在这个包中)
wrapper.java.classpath.4 = %basePath%/bin/bootstrap.jar
wrapper.java.classpath.5 = %basePath%/bin/tomcat-juli.jar

#Wrapper集成主类。有4种集成方式,适合tomcat这样启动使用一个类,
#停止使用另一个类的应用的是WrapperStartStopApp类
wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperStartStopApp

#tomcat应用参数,无需修改(第一个参数是tomcat的启动类)
wrapper.app.parameter.1=org.apache.catalina.startup.Bootstrap
wrapper.app.parameter.2=1
wrapper.app.parameter.3=start
wrapper.app.parameter.4=org.apache.catalina.startup.Bootstrap
wrapper.app.parameter.5=TRUE
wrapper.app.parameter.6=1
wrapper.app.parameter.7=stop

wrapper.working.dir = %basePath%/bin

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

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

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

#Tomcat的固定参数(一般不用修改)
wrapper.java.additional.1=-Djava.util.logging.config.file=%basePath%/conf/logging.properties
wrapper.java.additional.2 = -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager 
wrapper.java.additional.3 = -Djava.endorsed.dirs=%basePath%/endorsed -Dcatalina.base=%basePath% -Dcatalina.home=%basePath%
wrapper.java.additional.4 = -Djava.io.tmpdir=%basePath%/temp
wrapper.java.additional.5 = -Djava.net.preferIPv4Stack=true
wrapper.java.additional.6 = -XX:MaxNewSize=256m
wrapper.java.additional.7 = -XX:MaxPermSize=256m
wrapper.java.additional.8 = -XX:-UseGCOverheadLimit
wrapper.java.additional.9 = -Dcom.sun.management.jmxremote

wrapper.jmx=false
wrapper.on_exit.0=SHUTDOWN
wrapper.on_exit.default=RESTART

wrapper.ntservice.interactive = true
#服务开机启动
wrapper.ntservice.starttype=AUTO_START
wrapper.tray = true

#监测JVM死锁
wrapper.java.monitor.deadlock = true
wrapper.java.monitor.heap = true
wrapper.java.monitor.gc.restart = true

# Java Heap 初始化大小(单位:MB)
wrapper.java.initmemory=1024
# Java Heap 最大值(单位:MB)
wrapper.java.maxmemory=1024

5.注册为服务:

C:UsersliqiangDesktop
2	omcatapache-tomcat-7.0.72servicewrapper>binwrapper.exe -i ..confwrapper.conf
wrapperm | Exam Server service installed.

C:UsersliqiangDesktop
2	omcatapache-tomcat-7.0.72servicewrapper>sc qc examservice
[SC] QueryServiceConfig 成功

SERVICE_NAME: examservice
        TYPE               : 110  WIN32_OWN_PROCESS (interactive)
        START_TYPE         : 2   AUTO_START
        ERROR_CONTROL      : 1   NORMAL
        BINARY_PATH_NAME   : C:UsersliqiangDesktop
2	omcatapache-tomcat-7.0.72servicewrapperinwrapper.exe -s C
:UsersliqiangDesktop
2	omcatapache-tomcat-7.0.72servicewrapperconfwrapper.conf wrapper.console.flush=true wrapp
er.internal.namedpipe=1139632464
        LOAD_ORDER_GROUP   :
        TAG                : 0
        DISPLAY_NAME       : Exam Server
        DEPENDENCIES       :
        SERVICE_START_NAME : LocalSystem

C:UsersliqiangDesktop
2	omcatapache-tomcat-7.0.72servicewrapper>

6.启动服务并进行日志查看:

 

  由于项目中使用了log4j,所以现在可以从两个地方查看log日志。第一个是log4j指定的日志的输出的位置,第二个是wrapper.logs文件。

7.监测Tomcat的参数信息:

  可以jps+jmap进行查看(前提是安装JDK),如果没有安装JDK可以利用tomcat自带的manager项目进行监测(参考:https://www.cnblogs.com/qlqwjy/p/8037392.html)。如果需要对参数进行优化,只需要修改上面wrapper.conf文件即可。

  总结:

  上面还可以进行大量的优化,比如讲一些不用的文件删掉,将多个lib目录进行合并;

  至此完成了tomcat注册为web服务,项目中一般使用这种方式进行部署项目,而且mysql可以采用集成部署集成到系统中,到时候系统上线的时候只用一个压缩包传到服务器,避免大量的下载tomcat、mysql等以及大量的配置。我上个项目上线也确实是通过安装JDK、mysql、tomcat等进行部署安装的,采用这种集成的方式都不用安装JDK等软件,简化部署。

 5.linux环境下的注册为服务

   参考:https://www.cnblogs.com/zifengli/archive/2015/11/30/5007568.html

附件:官网的一份配置:

#encoding=UTF-8
# Configuration files must begin with a line specifying the encoding
#  of the the file.

#********************************************************************
# 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

# Include file problems can be debugged by removing the first '#'
#  from the following line:
##include.debug

# The Wrapper will look for either of the following optional files for a
#  valid License Key.  License Key properties can optionally be included
#  directly in this configuration file.
#include ../conf/wrapper-license.conf
#include ../conf/wrapper-license-%WRAPPER_HOST_NAME%.conf

# The following property will output information about which License Key(s)
#  are being found, and can aid in resolving any licensing problems.
#wrapper.license.debug=TRUE

#********************************************************************
# Wrapper Localization
#********************************************************************
# Specify the locale which the Wrapper should use.  By default the system
#  locale is used.
#wrapper.lang=en_US # en_US or ja_JP

# Specify the location of the Wrapper's language resources.  If these are
#  missing, the Wrapper will default to the en_US locale.
wrapper.lang.folder=../lang

#********************************************************************
# Wrapper Java Properties
#********************************************************************
# Java Application
#  Locate the java binary on the system PATH:
wrapper.java.command=java
#  Specify a specific java binary:
#set.JAVA_HOME=/java/path
#wrapper.java.command=%JAVA_HOME%/bin/java

# Tell the Wrapper to log the full generated Java command line.
#wrapper.java.command.loglevel=INFO

# Java Main class.  This class must implement the WrapperListener interface
#  or guarantee that the WrapperManager class is initialized.  Helper
#  classes are provided to do this for you.  See the Integration section
#  of the documentation for details.
wrapper.java.mainclass=org.tanukisoftware.wrapper.demo.DemoApp

# Java Classpath (include wrapper.jar)  Add class path elements as
#  needed starting from 1
wrapper.java.classpath.1=../lib/wrapperdemo.jar
wrapper.java.classpath.2=../lib/wrapper.jar

# Java Library Path (location of Wrapper.DLL or libwrapper.so)
wrapper.java.library.path.1=../lib

# Java Bits.  On applicable platforms, tells the JVM to run in 32 or 64-bit mode.
wrapper.java.additional.auto_bits=TRUE

# Java Additional Parameters
wrapper.java.additional.1=

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

# Maximum Java Heap Size (in MB)
#wrapper.java.maxmemory=64

# Application parameters.  Add parameters as needed starting from 1
wrapper.app.parameter.1=

#********************************************************************
# Wrapper Logging Properties
#********************************************************************
# Enables Debug output from the Wrapper.
# wrapper.debug=TRUE

# Format of output for the console.  (See docs for formats)
wrapper.console.format=PM

# Log Level for console output.  (See docs for log levels)
wrapper.console.loglevel=INFO

# Log file to use for wrapper output logging.
wrapper.logfile=../logs/wrapper.log

# Format of output for the log file.  (See docs for formats)
wrapper.logfile.format=LPTM

# Log Level for log file output.  (See docs for log levels)
wrapper.logfile.loglevel=INFO

# Maximum size that the log file will be allowed to grow to before
#  the log is rolled. Size is specified in bytes.  The default value
#  of 0, disables log rolling.  May abbreviate with the 'k' (kb) or
#  'm' (mb) suffix.  For example: 10m = 10 megabytes.
wrapper.logfile.maxsize=0

# Maximum number of rolled log files which will be allowed before old
#  files are deleted.  The default value of 0 implies no limit.
wrapper.logfile.maxfiles=0

# Log Level for sys/event log output.  (See docs for log levels)
wrapper.syslog.loglevel=NONE

#********************************************************************
# Wrapper General Properties
#********************************************************************
# Allow for the use of non-contiguous numbered properties
wrapper.ignore_sequence_gaps=TRUE

# Do not start if the pid file already exists.
wrapper.pidfile.strict=TRUE

# Title to use when running as a console
wrapper.console.title=Test Wrapper Sample Application

#********************************************************************
# Wrapper JVM Checks
#********************************************************************
# Detect DeadLocked Threads in the JVM. (Requires Standard Edition)
wrapper.check.deadlock=TRUE
wrapper.check.deadlock.interval=10
wrapper.max_failed_invocations=99
wrapper.console.fatal_to_stderr=FALSE
wrapper.console.error_to_stderr=FALSE
wrapper.check.deadlock.action=RESTART
wrapper.check.deadlock.output=FULL

# Out Of Memory detection.
#  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
# (Only match text in stack traces if -XX:+PrintClassHistogram is being used.)
#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 Notifications. (Requires Professional Edition)
#********************************************************************
# Common Event Email settings.
#wrapper.event.default.email.debug=TRUE
#wrapper.event.default.email.smtp.host=<SMTP_Host>
#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>

# Configure the log attached to event emails.
#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

# Enable specific event emails.
#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

# Specify custom mail content
wrapper.event.jvm_restart.email.body=The JVM was restarted.

Please check on its status.


#********************************************************************
# Wrapper Windows NT/2000/XP Service Properties
#********************************************************************
# 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.

# Name of the service
wrapper.name=testwrapper

# Display name of the service
wrapper.displayname=Test Wrapper Sample Application

# Description of the service
wrapper.description=Test Wrapper Sample Application Description

# Service dependencies.  Add dependencies as needed starting from 1
wrapper.ntservice.dependency.1=

# Mode in which the service is installed.  AUTO_START, DELAY_START or DEMAND_START
wrapper.ntservice.starttype=AUTO_START

# Allow the service to interact with the desktop.
wrapper.ntservice.interactive=false

  

参考Java Service Wrapper官网介绍:https://wrapper.tanukisoftware.com/doc/english/qna-service.html

 wrapper高级配置详解参考:https://blog.csdn.net/u010419967/article/details/37690269

补充:wrapper安装的服务不能正常启动

  报错Unable to execute Java command.  系统找不到指定的文件。 

  原因是找不到Java命令,解决办法就是修改wrapper.conf将java路径设为绝对路径,如下:

# Path to JVM executable. By default it must be available in PATH.
# Can be an absolute path, for example:
#wrapper.java.command=/path/to/my/jdk/bin/java
wrapper.java.command=C:Program FilesJavajdk1.8.0_121injava.exe
原文地址:https://www.cnblogs.com/qlqwjy/p/9492813.html