以Windows服務方式運行Java程序
如題,怎樣將Java程序變身為Windows服務,不要跟我說Win接口,我不熟。
一、將exe程序變為Win服務
即將java啟動批處理命令編譯為win程序,可通過 批處理潛行者V6.0或 quickbfc 3.6.1實現;
然后利用系統自帶的sc命令將其創建為系統服務:(這里為了測試效果,我加上了交互式運行服務的參數)
sc create test binPath= "C:\FFE.exe" type= own type= interact start= auto
注意,坑跌的windows命令一向是不走尋常路:
- “=”后面一定要有空格
- 如果要使用type參數,則一定要設置兩個,比如上面的栗子中加了第一個”獨立運行“,后面還要跟一個”交互式“才能最終生效,否則會報錯:[SC] CreateService FAILED 87
Using some of the options will trigger a "[SC] CreateService FAILED 87" this usually means the option used like "type" needs another declaration. In case for instance when using type= interact, the type= option must be declared again with an alternative type like own. So effectivly the service type will be type= own interactive.
創建完成之后就可以啟動服務:net start test
發現程序正常啟動了,但是服務一直是啟動狀態,把程序關閉后,服務又變成了停止狀態。Why?
因為系統服務并不知道你程序啟動到什么狀態才算是啟動成功,也不知道程序停止是正常結束還是異常退出。
歸根結底,就是通過sc命令將一般程序添加為系統服務的方式沒有實現Win服務接口,不滿足作為一個標準的daemon程序的條件。
在網上搜索一番,發現還有微軟的開發工具可以利用:使用srvany.exe將任何程序作為Windows服務運行
上面這篇文章寫得很棒,作者還開發了一個輕巧的工具SrvanyUI方便創建自定義服務。
但是我經過試驗沒有成功,原因不明。后臺監控發現java程序閃現之后迅速關閉,可能是因為classpath設置錯誤。
總而言之,這種方式還是不夠靈活,出錯沒有任何提示,只能通過經驗去排錯;
另外,如文中所說,該工具已不被微軟支持了,并且win7以上的版本可能會出現兼容問題。
二、來自Java世界的工具
How to create a windows service from java app?
各種牛人都在這篇問答里發表了他們的看法:
- The Java Service Wrapper,目前業界最知名、最成熟的解決方案
JSW我使用了較長的時間,穩定性和擴展性都不錯,高級版本還提供了對Java異常的處理,比如OOM產生時可以選擇是否自動重啟服務。
但不足之處是,收費、64位版本需要購買Licence。放在5年前,或許不用擔憂是否需要64位JVM,但如今,32位僅1.5G的堆內存略顯不足。
一個 wrapper.conf配置文件示例如下:(官方下載包有更詳細的例子和說明)
wrapper.java.command="C:\Program Files\Java\jdk1.7.0_72\bin\java" wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp wrapper.java.classpath.1=../test.jar wrapper.java.classpath.2=wrapper.jar wrapper.java.classpath.3=../lib/* wrapper.java.library.path.1=. wrapper.java.additional.1= -Xms512m wrapper.java.additional.2= -Xmx512m wrapper.java.initmemory=256 wrapper.java.maxmemory=512 wrapper.app.parameter.1=test.Main wrapper.app.parameter.2=arg1 wrapper.console.format=PM wrapper.console.loglevel=INFO wrapper.logfile=../log/test.log wrapper.logfile.format=LPTM wrapper.logfile.loglevel=INFO wrapper.logfile.maxsize=0 wrapper.logfile.maxfiles=0 wrapper.syslog.loglevel=NONE wrapper.console.title=Test_Service wrapper.ntservice.name=Test_Service wrapper.ntservice.displayname=Test_Service wrapper.ntservice.description=Test_Service wrapper.ntservice.dependency.1= wrapper.ntservice.starttype=AUTO_START wrapper.ntservice.interactive=false
- Yet Another Java Service Wrapper,類似JSW的開源實現版本
- Apache Commons Daemon,著名的Apache Commons工具包的成員
- WinRun4J,java2exe2service集合,額外提供 eclipse插件一鍵導出!
- JSmooth(07年后未更新)
- NSSM - the Non-Sucking Service Manager(名字很叼的樣子,提供GUI方式將EXE打包為服務,與上文的SrvanyUI類似)
- WINDOWS SERVICE WRAPPER(6年未更新且依賴.Net)
- FireDaemon(看到Buy Now兩個字后我就X了)
-
javaservice(06年后未更新,使用方法不詳)
-
Java Service Launcher(小巧,支持64位JVM以及JRockit等第三方虛擬機,可惜文檔比較簡陋)
-
Launch4j,一個將Jar打包為exe的工具,可惜的是使用XML配置,個人無感
-
更多開源工具見:Java開源打包工具
</ul>
或許YAJSW出現就是為了替換JSW,因為它是開源免費的,且支持從JSW快速無縫遷移。但是,有個哥們都說被它19M的下載包給嚇到了…所以……
以下工具本人并未測試,但不代表不適用:
三、久違的 Apache Commons Daemon
先來說說情懷:Tomcat,相信很多同學從第一天學習Java的時候就開始熟知。看到ACD的圖標后才發現,原來Tomcat win安裝版就是用的它!
再來說說用法:Win版的入口程序是procrun,用它來創建一個服務是如此之簡單:
set APP_HOME=D:\ set CP=%APP_HOME%\test.jar;%APP_HOME%\lib\* REM 創建服務 prunsrv //IS//test_service --DisplayName=test_service --Install=%APP_HOME%\bin\prunsrv.exe --StartMode=jvm --StopMode=jvm --Startup=auto --JavaHome="C:\Program Files\Java\jdk1.7.0_72\" --JvmMs=2048 --JvmMx=2048 --JvmSs=128 ++JvmOptions=-server;-XX:+UseParallelGC;-XX:ParallelGCThreads=4;-XX:+UseParallelOldGC;-XX:+UseAdaptiveSizePolicy --Classpath=%CP%" --StartClass=com.test.Main --StopClass=com.test.Main --StopMethod=stop --LogPath=%APP_HOME%\log --StdOutput=auto --StdError=auto REM 刪除服務 prunsrv //DS//test_service
參數很多,看看注釋就明白了,這里也有中文翻譯:Commons Daemon 之 procrun。
此外,Wiki頁上有一些答問和一個Java主程序栗子。有幾點需要注意的是:
- --LogPath 一定要指定,下面的報錯信息都可在日志文件中找到:commons-daemon.2014-11-11.log
- --JavaHome 一定要寫JRE路徑,否則可能報錯:Prunsrv.C Failed Creating Java
- --Classpath 一定要寫成變量,否則會添加失敗,原因不詳
- --Classpath=%CP%" 這句最后多出的那個雙引號一定要寫,否則創建失敗,原因不詳!
- --StopMethod=stop 關閉服務的時候會自動調用該stop方法,具體寫法如下:
public static void stop(String[] args) { System.out.println("服務關閉了"); System.exit(0); }
Procrun不僅可將Java類生成服務,也可將exe變為服務,詳見參數設置。
參考:用common-deamon構建java后臺服務、Windows 64位環境的Java 服務配置
四、最后來看強大的WinRun4J
先來說說它的弊端:需要一個入口類,依賴WinRun4J.jar包,相比ACD有一定耦合度,而非直接用主啟動類。除此之外,一切看起來都不錯~
The only drawback is that it requires a special class for working as a service (instead of simply calling standard main class)官網上有個生成服務的栗子,下載的包里也有,但是都有點問題:
import org.boris.winrun4j.AbstractService; import org.boris.winrun4j.EventLog; import org.boris.winrun4j.ServiceException;public class ServiceTest extends AbstractService {
public int serviceMain(String[] args) throws ServiceException { int count = 0; while (!shutdown) { try { Thread.sleep(1000); } catch (InterruptedException e) { } if (++count % 10 == 0) { EventLog.report("test", EventLog.INFORMATION, "test..." + count); System.out.println("test log...." + count); } } System.out.println("service shutdown..."); return 0; } public boolean isShutdown() { System.out.println("isShutdown called..."); return super.isShutdown(); }
}</pre>
上面類中調用 EventLog.report方法生成的日志只會寫到系統日志里,只有在 計算機管理 - 系統工具 - 事件查看器 - 應用程序 中才能看到
對應的日志文件在XP系統中的位置是:C:\WINDOWS\system32\config\SysEvent.Evt
顯然我們更希望日志可控,而不是被操作系統接管。但是我沒有找到合適的參數來設置,只能通過Java程序來指定。
將上面的類編譯后生成class文件,然后再來編輯配置文件WinRun4Jc.ini:
service.class=ServiceTest service.id=WinRun4J_Test service.name=WinRun4J_Test service.description=test WinRun4J. classpath.1=. classpath.2=D:\winrun4j\bin\WinRun4J.jar log=test.log注意了:
- WinRun4Jc.ini與 WinRun4Jc.exe必須位于相同目錄且名稱要一致,因為沒有參數可以指定配置文件路徑…
- 以上參數缺一不可,并且 service.id與 service.name一定要寫相同的服務名稱
- classpath.2指定為 WinRun4J.jar的路徑,因為上面的服務入口類實現了該包中的某類
通過以下命令創建和刪除服務:
WinRun4Jc --WinRun4J:RegisterService WinRun4Jc --WinRun4J:UnregisterService
WinRun4J還提供了Eclipse插件以及給exe程序增加ico圖標的小工具,用法很簡單,官網上也有說明。
不管怎么說,WinRun4J相當于ACD和 Launch4j的合體,雖然整體功能沒有兩者強大,但是也都做得不錯,
尤其是對于使用eclipse的同學可是方便了不少,看看它貼心的導出功能即可見一斑:
來自:http://my.oschina.net/cwalet/blog/343687