需求: 由於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包瘦身與服務部署註冊的完整過程,其中不涉及到業務代碼的修改。只需要嵌入啓動類即可。