spring boot 使用maven和fat jar/war運行應用程序的對比


使用maven和fat jar/war運行應用程序的對比

簡介

上篇文章我們介紹了Spring boot的fat jar/war包,jar/war包都可以使用 java -jar 命令來運行,而maven也提供了mvn spring-boot:run 命令來運行應用程序,下面我們看看兩者有什麼不同。

Spring Boot Maven Plugin

上篇文章我們提到了Spring Boot Maven Plugin,通過使用該插件,可以有效的提高部署效率,並打包成爲fat jar/war包。

在打包成fat jar/war包的時候,背後實際上做了如下的事情:

  1. 管理了classpath的配置,這樣我們在運行java -jar的時候不用手動指定-cp 。
  2. 使用了自定義的ClassLoader來加載和定位所有的外部jar包依賴。並且所有的依賴jar包已經被包含在這個fat包裏面了。
  3. 通過manifest自動查找main() ,這樣我們就不需要在java -jar中手動指定main方法。

使用Maven命令來運行應用程序

要使用maven命令來運行應用程序可以在程序的根目錄下面執行:

mvn spring-boot:run

它會自動下載所需要的依賴,並運行,運行日誌如下:

mvn spring-boot:run
[INFO] Scanning for projects...
[INFO] 
[INFO] -------------------< com.flydean:springboot-fatjar >--------------------
[INFO] Building springboot-fatjar 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] >>> spring-boot-maven-plugin:2.2.2.RELEASE:run (default-cli) > test-compile @ springboot-fatjar >>>
[INFO] 
[INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ springboot-fatjar ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 0 resource
[INFO] Copying 0 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ springboot-fatjar ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ springboot-fatjar ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.

[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ springboot-fatjar ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] <<< spring-boot-maven-plugin:2.2.2.RELEASE:run (default-cli) < test-compile @ springboot-fatjar <<<
[INFO] 
[INFO] 
[INFO] --- spring-boot-maven-plugin:2.2.2.RELEASE:run (default-cli) @ springboot-fatjar ---
[INFO] Attaching agents: []

作爲fat jar/war包運行應用程序

如果想打包成fat jar/war, 需要使用Maven Spring Boot plugin,如下所示,否則打包出來的jar包並不包含外部依賴:

<build>
    <plugins>
        ...
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        ...
    </plugins>
</build>

如果我們的代碼包含了多個main class, 需要手動指定具體使用哪一個, 有兩種設置方式:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <executions>
        <execution>
            <configuration>
                <mainClass>com.flydean.FatJarApp</mainClass>
            </configuration>
        </execution>
    </executions>
</plugin>

或者設置star-class屬性:

<properties>
    <start-class>com.flydean.FatJarApp</start-class>
</properties>

使用 mvn clean package 即可打包程序,然後使用java -jar target/springboot-fatwar-0.0.1-SNAPSHOT.war
即可運行。

詳解War文件

將打包好的war文件解壓,我們看下War文件的結構:

裏面有三部分:

  • META-INF, 裏面包含有自動生成的MANIFEST.MF
  • WEB-INF/classes, 包含了編譯好的class文件
  • WEB-INF/lib,包含了war的依賴jar包和嵌入的Tomcat jar包。
  • WEB-INF/lib-provided,包含了embedded模式運行所需要但是在部署模式不需要的額外的依賴包。
  • org/springframework/boot/loader,裏面是Spring boot自定義的類加載器,這些類加載器負責加載外部依賴,並且使他們在運行時可用。

我們再看下MANIFEST.MF文件的內容:

Manifest-Version: 1.0
Implementation-Title: springboot-fatwar
Implementation-Version: 0.0.1-SNAPSHOT
Start-Class: com.flydean.FatWarApp
Spring-Boot-Classes: WEB-INF/classes/
Spring-Boot-Lib: WEB-INF/lib/
Build-Jdk-Spec: 1.8
Spring-Boot-Version: 2.2.2.RELEASE
Created-By: Maven Archiver 3.4.0
Main-Class: org.springframework.boot.loader.WarLauncher

主要關注兩行:

Start-Class: com.flydean.FatWarApp
Main-Class: org.springframework.boot.loader.WarLauncher

一個是啓動類就是我們自己寫的,一個是main類這個是Spring boot自帶的。

詳解jar文件

我們再來看下jar文件:

jar文件和war文件有一點不同,沒有WEB-INF,改成了BOOT-INF。

  • 我們所有的自己的class都在BOOT-INF/classes下面。
  • 外部依賴在BOOT-INF/lib下。

我們再看下MANIFEST.MF文件有什麼不同:

Manifest-Version: 1.0
Implementation-Title: springboot-fatjar
Implementation-Version: 0.0.1-SNAPSHOT
Start-Class: com.flydean.FatJarApp
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Build-Jdk-Spec: 1.8
Spring-Boot-Version: 2.2.2.RELEASE
Created-By: Maven Archiver 3.4.0
Main-Class: org.springframework.boot.loader.PropertiesLauncher

我們可以看到Start-Class還是一樣的,但是Main-Class是不一樣的。

如何選擇

既然有兩種方式來運行應用程序,一種是使用mvn命令,一種是使用fat jar/war文件,那我們該怎麼選擇呢?

通常情況下,如果我們是在線下的開發環境,可以直接使用mvn命令,mvn命令需要依賴於源代碼,我們可以不斷的修改源代碼,方便開發。

如果是在線上環境,那麼我們就需要使用fat jar/war了,這樣的外部依賴比較小,我們不需要在線上環境部署maven環境,也不需要源代碼,只要一個java的運行時環境就可以了。

本文的代碼請參考https://github.com/ddean2009/learn-springboot2/tree/master/springboot-fatwar

更多教程請參考 flydean的博客

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