以Windows服務方式運行Java程序

jopen 10年前發布 | 163K 次閱讀 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
參考: 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

發現程序正常啟動了,但是服務一直是啟動狀態,把程序關閉后,服務又變成了停止狀態。Why?

因為系統服務并不知道你程序啟動到什么狀態才算是啟動成功,也不知道程序停止是正常結束還是異常退出。

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

在網上搜索一番,發現還有微軟的開發工具可以利用:使用srvany.exe將任何程序作為Windows服務運行

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

但是我經過試驗沒有成功,原因不明。后臺監控發現java程序閃現之后迅速關閉,可能是因為classpath設置錯誤。

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

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


二、來自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
  • Yet Another Java Service Wrapper,類似JSW的開源實現版本
  • </ul>

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

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

    以下工具本人并未測試,但不代表不適用:

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


    三、久違的 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
    • --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的同學可是方便了不少,看看它貼心的導出功能即可見一斑:

    以Windows服務方式運行Java程序

    來自:http://my.oschina.net/cwalet/blog/343687

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!