以Windows服務方式運行Java程序

如題,怎樣將Java程序變身爲Windows服務,不要跟我說Win接口,我不熟。 php

1、將exe程序變爲Win服務

即將java啓動批處理命令編譯爲win程序,可經過 批處理潛行者V6.0或 quickbfc 3.6.1實現; html

而後利用系統自帶的sc命令將其建立爲系統服務:(這裏爲了測試效果,我加上了交互式運行服務的參數) java

sc create test binPath= "C:\FFE.exe" type= own type= interact start= auto

注意,坑跌的windows命令一貫是不走尋常路: shell

  • 「=」後面必定要有空格
  • 若是要使用type參數,則必定要設置兩個,好比上面的栗子中加了第一個」獨立運行「,後面還要跟一個」交互式「才能最終生效,不然會報錯:[SC] CreateService FAILED 87
參考: How to create windows services (Command Line)
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 apache

發現程序正常啓動了,可是服務一直是啓動狀態,把程序關閉後,服務又變成了中止狀態。Why? windows

由於系統服務並不知道你程序啓動到什麼狀態纔算是啓動成功,也不知道程序中止是正常結束仍是異常退出。 tomcat

歸根結底,就是經過sc命令將通常程序添加爲系統服務的方式沒有實現Win服務接口,不知足做爲一個標準的daemon程序的條件。 app

在網上搜索一番,發現還有微軟的開發工具能夠利用:使用srvany.exe將任何程序做爲Windows服務運行 eclipse

上面這篇文章寫得很棒,做者還開發了一個輕巧的工具SrvanyUI方便建立自定義服務。 jvm

可是我通過試驗沒有成功,緣由不明。後臺監控發現java程序閃現以後迅速關閉,多是由於classpath設置錯誤。

總而言之,這種方式仍是不夠靈活,出錯沒有任何提示,只能經過經驗去排錯;

另外,如文中所說,該工具已不被微軟支持了,而且win7以上的版本可能會出現兼容問題。


2、來自Java世界的工具

How to create a windows service from java app?

各類牛人都在這篇問答裏發表了他們的見解:

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

或許YAJSW出現就是爲了替換JSW,由於它是開源免費的,且支持從JSW快速無縫遷移。可是,有個哥們都說被它19M的下載包給嚇到了…因此……

  • WinRun4J,java2exe2service集合,額外提供 eclipse插件一鍵導出!

如下工具本人並未測試,但不表明不適用:

  • FireDaemon(看到Buy Now兩個字後我就X了)


3、久違的 Apache Commons Daemon

先來講說情懷:Tomcat,相信不少同窗從第一天學習Java的時候就開始熟知。看到ACD的圖標後才發現,原來Tomcat win安裝版就是用的它!

再來講說用法:Win版的入口程序是procrun,用它來建立一個服務是如此之簡單:

set APP_HOME=D:\
set JAVA_HOME="C:\Program Files\Java\jdk1.7.0_72\"
set PR_CLASSPATH=%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=%JAVA_HOME% --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
  • --Classpath 必定要寫成變量,變量名必定要爲 PR_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 服務配置


4、最後來看強大的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();
	}
}

上面類中調用 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的同窗但是方便了很多,看看它貼心的導出功能便可見一斑:

相關文章
相關標籤/搜索