jar文件瘦身與部署爲Windows服務

需求: 由於spring boot 結合cloud 可以有多個微服務,可以打很多jar包,其中有很多maven庫是重複的,package生成的jar中由於重複會佔用大量的體積。造成在操作系統上部署時佔用磁盤空間,安裝過程也較慢。 同時,爲了便於在操作系統上一鍵化部署jar服務,可以編寫install.exe或install.sh來實現。在雲平臺上由於有install文件,也可以方便以組件的形式安裝部署和卸載。


目前我瞭解的將Java程序部署爲Windows服務的方式有java service wrapper和Apache Commons Daemon兩種。

1.概述

1.1  爲什麼使用Apache Commons Daemon

      java service wrapper使用簡單,集成方法簡單,不修改任何代碼,一般情況下已滿足需求。但是,java service wrapper只對java程序的開啓及關閉進行操作,若需要對程序啓動前及關閉前進行一些自定義的操作(如啓動時初始化工作,關閉時釋放某些資源或進行特殊操作),此時就可以使用apache commons daemon了。

1.2  Apache Commons Daemon介紹

      Apache common deamon是用來提供java服務的安裝,實現將一個普通的 Java 應用變成系統的一個後臺服務,在linux下部署爲後臺運行程序,在windows部署爲windows服務(著名的tomcat就是使用它實現啓動及停止的。提供啓動、停止、卸載等操作)。詳細介紹可見commons-daemon官網(http://commons.apache.org/proper/commons-daemon/index.html)。相對java service wrapper,commons daemon需要自己寫少許代碼,即按規定要求編寫程序啓動及關閉的入口類,僅此而已。

2.下載安裝

下載commons-daemon主程序commons-daemon-1.1.0-bin.zip,解壓出commons-daemon-1.1.0.jar

下載procrun,官網的procrun頁面只對它的使用進行講解,在哪裏下載即沒有提及,這裏特別提醒一下,需要在這裏(http://www.apache.org/dist/commons/daemon/binaries/windows/)下載procrun,下載commons-daemon-1.1.0-bin-windows.zip。解壓出文件如下:

將你的Java程序打成jar包,commons-daemon-1.1.0.jar和prunsrv.exe,prunmgr.exe,install.bat,uninstall.bat放到同一個文件夾下(注意64位的機器要用amd64文件夾下的prunsrv.exe)

3.spring boot 程序啓動類實現

 pom.xml文件裏新增loader包支持

      <!-- 服務jsvc 方式註冊部署 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-loader</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-daemon</groupId>
            <artifactId>commons-daemon</artifactId>
            <version>1.1.0</version>
        </dependency>

pom.xml文件裏配置bulid 插件。

 

在***Aplication.class 相同目錄下,新增一個啓動類。

package com.mboot.wheelbase;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.loader.PropertiesLauncher;

/**
 * Daemon jsvc方式註冊部署jar服務時的啓動類
 */
public class DaemonMainLauncher  extends PropertiesLauncher {
    private static Logger LOGGER = LoggerFactory.getLogger(DaemonMainLauncher.class);

    private static DaemonMainLauncher daemonMainLauncher = null;

    public static void init(String[] args) {
    }

    public static void start(String[] args) {
        if (daemonMainLauncher == null)
            daemonMainLauncher = new DaemonMainLauncher();
        try
        {
            args = daemonMainLauncher.getArgs(args);
            daemonMainLauncher.launch(args);
        } catch (Exception ex) {
            System.exit(1);
        }
    }

    public static void destroy() {
    }

    public static void start() {
        String[] args = { "start" };
        start(args);
    }

    public static void stop(String[] args) {
        try {
            System.exit(0);
        } catch (Exception ex) {
            System.exit(1);
        }
    }

    public static void stop() {
        String[] args = { "stop" };
        stop(args);
    }

    public static void main(String[] args)
    {
        try {
            String mode = (args != null) && (args.length > 0) ? args[0] : null;
            if ("start".equals(mode)) {
                start(args);
            }
            else if ("stop".equals(mode)) {
                stop(args);
            }
            else
                start(args);
        }
        catch (Exception e) {
            System.exit(1);
        }
    }
}

 

pom.xml文件裏配置bulid 插件。

    <build>

        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <skip>true</skip>
                    <layout>ZIP</layout>
                    <includes>

                        <exclude>
                            <groupId>com.mboot</groupId>
                            <artifactId>wheel-base</artifactId> <!--服務名,同artifactId中內容 -->
                        </exclude>

                    </includes>
                </configuration>
            </plugin>

        </plugins>

    </build>

       編譯打包生成wheel-base-0.0.1.jar 包,這個包即爲瘦身後的包,大概只有幾十KB,非常小。它不包含maven中引入的軟件依賴庫。爲了部署時不缺少依賴庫,需要註釋掉bulid中<configuration></configuration>裏面的內容後,重新編譯生成一個*wheel-base-0.0.1.jar。將第二次生成的大體積jar包中的lib複製出來作爲接下來的依賴庫使用。

下面來寫服務安裝腳本  install.bat

@echo off

rem 設置程序名稱
set SERVICE_EN_NAME=WheelBase
set SERVICE_CH_NAME=WheelBase工作流引擎
set DESCRIPTION=wheel-base工作組件

rem 設置java路徑
set _JAVA_HOME=%JAVA_HOME%


rem 設置程序依賴及程序入口類
set BASEDIR=%CD%
set BPM_LIBS=%BASEDIR%\server\lib
set BPM_MAIN_LIBS=%BASEDIR%\server\main_lib
set BPM_EXT_LIBS=%BASEDIR%\server\ext_lib
set BPM_LOG=%BASEDIR%\config\log
set _main=com.mboot.wheelbase.WheelBaseApplication
set _LauncherClass=com.mboot.wheelbase.DaemonMainLauncher
set CLASSPATH=%BPM_LIBS%\*;%BPM_MAIN_LIBS%\*;%BPM_EXT_LIBS%\*;%BPM_LOG%;%_JAVA_HOME%\lib\dt.jar;%_JAVA_HOME%\lib\tools.jar;%BPM_MAIN_LIBS%\wheel-base-0.0.1.jar;


rem 設置prunsrv路徑 
set SRV=%CD%\prunsrv.exe

rem 設置日誌路徑及日誌文件前綴
set LOGPATH=%BASEDIR%\tmp\logs

rem 輸出信息
echo SERVICE_NAME: %SERVICE_EN_NAME%
echo JAVA_HOME: %JAVA_HOME%
echo MAIN_CLASS: %MAIN_CLASS%
echo prunsrv path: %SRV%

rem 設置jvm
if "%JVM%" == "" goto findJvm
if exist "%JVM%" goto foundJvm
:findJvm
set "JVM=%_JAVA_HOME%\jre\bin\server\jvm.dll"
if exist "%JVM%" goto foundJvm
echo can not find jvm.dll automatically,
echo please use COMMAND to localation it
echo for example : set "JVM=%_JAVA_HOME%\jre\bin\server\jvm.dll"
echo then install service
goto end
:foundJvm

rem 安裝
"%SRV%" //IS//"%SERVICE_EN_NAME%" --DisplayName="%SERVICE_EN_NAME%" --Classpath="%CLASSPATH%"  --Description="%DESCRIPTION%" --Install="%SRV%" --JavaHome="%_JAVA_HOME%" --Jvm="%JVM%" --JvmMs=256 --JvmMx=1024 --Startup=auto --JvmOptions=-Djcifs.smb.client.dfs.disabled=false ++JvmOptions=-Djava.io.tmpdir="%CD%"/tmp ++JvmOptions=-Dloader.main=%_main% ++JvmOptions=-DBPM_HOME=%BASEDIR% ++JvmOptions=-Djcifs.resolveOrder=DNS --StartPath="%BASEDIR%" --StartMode=jvm  --StartClass=%_LauncherClass% --StartMethod=start --StopPath="%BASEDIR%" --StopMode=jvm --StopClass=%_LauncherClass% --StopMethod=stop --LogPath="%LOGPATH%" --StdOutput=auto --StdError=auto 

:end

    要注意的是classpath中的路徑應有你Java程序的所有依賴包以及你自己打包程序的那個jar包,上述解壓出的commons-daemon-1.1.0.jar也應該在這個路徑中。
%SRV%  爲prunsrv.exe所在路徑

%LOGPATH%  爲日誌路徑

--StartMethod   爲程序入口開始方法(對應部署服務之後的啓動)   必須要在自己打包的Java程序中寫這個方法,根據自己的業務邏輯編寫即可。(在某些博客中看到這個方法必須命名爲start,實踐證明並不需要,但你一定要有這個開始方法)。

--StopMethod   爲程序入口結束方法(對應部署服務後的停止)   必須要在自己打包的Java程序中寫這個方法,根據自己的業務邏輯編寫即可。(在某些博客中看到這個方法必須命名爲start,實踐證明並不需要,但你一定要有這個結束方法)。

要格外注意的是以上兩個方法一定要聲明爲public static void,並且一定要帶參數(如string[] args),不然Apache Commons Daemon會報錯,詳情請見Apache Commons Daemon的官方說明文檔。建議你所打包的Java入口程序中不寫main方法,只寫開始和結束方法。
 

再來寫服務卸載腳本  uninstall.bat

@echo off
set BASEDIR=%CD%
set SERVICE_NAME=WheelBase
set "SRV=%BASEDIR%\prunsrv.exe"

%SRV% //DS//%SERVICE_NAME%

:end

簡言之,到這一步爲止,你的目錄結構下應該有你自己打的jar包,commons-daemon-1.1.0.jar,prunsrv.exe,prunmgr.exe,install.bat,uninstall.bat

其目錄結構如下,其中conf,server,tmp的子目錄按照install.bat 文件中配置的文件路徑創建即可:


此時運行install.bat腳本即可,運行之後會發現操作系統的服務中多了一個WheelBase服務,可以正常的啓動和停止。tmp目錄下中的log目錄會記錄啓動日誌,如下:

該日誌記錄了服務註冊的成功與失敗,以及停止卸載等。

 

在操作系統的服務中,點擊“啓動”後,spring boot 啓動成功,表示服務註冊部署成功。

如果要卸載該服務,運行uninstal.exe即可。

以上就是jar包瘦身與服務部署註冊的完整過程,其中不涉及到業務代碼的修改。只需要嵌入啓動類即可。

 

 

 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章