有時候咱們但願咱們java寫的程序做爲服務註冊到系統中,Java Service Wrapper(下面簡稱wrapper)是目前較爲流行的將Java程序部署成Windows服務的解決方案, 本文將討論如何使用wrapper把咱們的程序打包成WIN服務! html
主要做用有:java
1.打包服務mysql
2.設置JVM參數linux
3.全部的日誌能夠輸出到指定文件web
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包:sql
將上面程序也打成包:(使用eclipse打包或者直接Jdk自帶的jar打包)apache
1.下載serviceWrapper包
下載地址:http://qiaoliqiang.cn/fileDown/wrapper-windows-x86-32-3.5.25.zip編程
下載後是一個壓縮包,解壓目錄以下:bootstrap
2.開始註冊一個簡單的服務:
1. 準備一個目錄,例如我在桌面建了一個SW目錄,並在裏面新建以下結構的目錄: 接下來全文的%EXAMPLE_HOME% 就是我新建的SW目錄名稱windows
%EXAMPLE_HOME%\ %EXAMPLE_HOME%\bin\ %EXAMPLE_HOME%\conf\ %EXAMPLE_HOME%\lang\ %EXAMPLE_HOME%\lib\ %EXAMPLE_HOME%\mylib\ %EXAMPLE_HOME%\logs\
以下:lang目錄是存放支持其餘語言的語言包,通常用不到
2. 而後將咱們下載的wrapper目錄下的文件拷貝到咱們上面建的目錄:
%WRAPPER_HOME%\bin\wrapper.exe -> %EXAMPLE_HOME%\bin\wrapper.exe %WRAPPER_HOME%\lib\wrapper.jar -> %EXAMPLE_HOME%\lib\wrapper.jar
%WRAPPER_HOME%\lib\wrapper.dll -> %EXAMPLE_HOME%\lib\wrapper.dll
%WRAPPER_HOME%\conf\wrapper.conf -> %EXAMPLE_HOME%\conf\wrapper.conf
將本身程序打成的包以及本身程序依賴的包放到mylib:
3.修改配置文件 %EXAMPLE_HOME%\conf\wrapper.conf
#java.exe所在位置
wrapper.java.command=C:\Program Files\Java\jdk1.7.0_80\bin\java.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:\Users\Administrator>cd C:\Users\Administrator\Desktop\SW C:\Users\Administrator\Desktop\SW>bin\wrapper.exe -c ..\conf\wrapper.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 Files\Java\jdk1.7.0_80\bin\java.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:\Users\Administrator\Desktop\SW\bin\..\lib\wrapper.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:\Users\Administrator\Desktop\SW\lib\wrapper.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)將程序註冊爲服務:
bin\wrapper.exe -i ..\conf\wrapper.conf
結果:
wrapper | Hello World Server service installed.
(3)啓動服務:
net start helloworld
或者:
bin\wrapper.exe -t ..\conf\wrapper.conf
啓動以後咱們回看到程序輸出在logs\wrapper.log文件內:
(4)中止服務
net stop helloword
或者
bin\wrapper.exe -p ..\conf\wrapper.conf
(5)刪除服務
sc delete helloword
或者
bin\wrapper.exe -r ..\conf\wrapper.conf
-----------上面是在系統有Java環境的狀況下的設置,如今假設咱們不存在Java運行環境,也就是沒有JRE與JDK:-------------
(1)拷貝java安裝目錄下的JRE(包含bin目錄和相關lib)目錄到上面的目錄%EXAMPLE_HOME%,以下:
jre目錄下:
(2)修改配置文件,利用咱們上面的jre目錄下的jar包和bin\java.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:\Users\liqiang\Desktop\xxx\SW>bin\wrapper.exe -c ..\conf\wrapper.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: "..\jre\bin\java.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:\Users\liqiang\Desktop\xxx\SW\bin\..\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:\Users\liqiang\Desktop\xxx\SW\lib\wrapp 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:\Users\liqiang\Desktop\xxx\SW>bin\wrapper.exe -i ..\conf\wrapper.conf wrapperm | Hello World Server service installed. C:\Users\liqiang\Desktop\xxx\SW>java 'java' 不是內部或外部命令,也不是可運行的程序 或批處理文件。 C:\Users\liqiang\Desktop\xxx\SW>javac 'javac' 不是內部或外部命令,也不是可運行的程序 或批處理文件。
爲了驗證咱們的服務是使用的jre目錄下的JDK,咱們能夠將jre目錄刪掉進行測試,或者是將配置文件中jre\lib的引入註釋掉進行測試。
如今咱們將jre目錄刪掉,啓動服務報錯以下:
在wrapper.log中查看到的日誌文件以下:
至此咱們實現了簡單的有JRE與無JRE兩種狀況的註冊服務,實際沒有JRE環境的時候咱們只須要將咱們的JRE附到目錄中而且在wrapper.conf中指明所在路徑便可。
補充1.:上面配置會致使JVM不斷重啓,須要加JVM參數以及設置,同時設置服務開機啓動:而且使用一變量記住咱們的項目路徑;修改wrapper.conf而且刪掉服務從新添加:
#定義了一個根路徑,注意set和.之間沒有空格,下面就能夠用%basePath%取此變量 set.basePath=C:\Users\liqiang\Desktop\xxx\SW #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:\Users\liqiang\Desktop\xxx\SW>bin\wrapper.exe -r ..\conf\wrapper.conf wrapperm | Hello World Server service removed.
C:\Users\liqiang\Desktop\xxx\SW>bin\wrapper.exe -c ..\conf\wrapper.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:\Users\liqiang\Desktop\xxx\SW\jre\bin\java.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:\Users\liqiang\Desktop\xxx\SW\bin\..\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:\Users\liqiang\Desktop\xxx\SW\lib\wrapp 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:\Users\liqiang\Desktop\xxx\SW>bin\wrapper.exe -i ..\conf\wrapper.conf wrapperm | Hello World Server service installed.
若是咱們想檢測JVM參數能夠用jps+jmap監測便可:
C:\Users\liqiang>jps 505668 Jps 504320 WrapperSimpleApp 487768 C:\Users\liqiang>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.25\bin中的文件複製到咱們的%EXAMPLE_HOME%\bin目錄下)
咱們只須要點擊上面的bat文件便可實現上面的操做。
*************************
我已經將個人一個例子上傳到個人服務器,下載地址:http://qiaoliqiang.cn/fileDown/serviceWrapperExample.zip
下載解壓以後只須要將本身程序打的包以及依賴包放到mylib目錄下,修改conf\wrapper.conf文件中下面兩處
set.basePath=C:\Users\liqiang\Desktop\xxx\SW #替換爲本身的目錄
#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:\Users\liqiang\Desktop\logTest #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:\Users\liqiang>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測試控制檯:
logs\wrapper.log文件內容以下:
E:\test.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:\Users\liqiang\Desktop\n2\tomcat\apache-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:\Users\liqiang\Desktop\n2\tomcat\apache-tomcat-7.0.72\servicewrapper>bin\wrapper.exe -i ..\conf\wrapper.conf wrapperm | Exam Server service installed. C:\Users\liqiang\Desktop\n2\tomcat\apache-tomcat-7.0.72\servicewrapper>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:\Users\liqiang\Desktop\n2\tomcat\apache-tomcat-7.0.72\servicewrapper\bin\wrapper.exe -s C :\Users\liqiang\Desktop\n2\tomcat\apache-tomcat-7.0.72\servicewrapper\conf\wrapper.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:\Users\liqiang\Desktop\n2\tomcat\apache-tomcat-7.0.72\servicewrapper>
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.\n\nPlease check on its status.\n #******************************************************************** # 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 Files\Java\jdk1.8.0_121\bin\java.exe