Spring Boot 打包成的可執行 jar ,爲何不能被其餘項目依賴?

前兩天被人問到這樣一個問題:java

「鬆哥,爲何個人 Spring Boot 項目打包成的 jar ,被其餘項目依賴以後,老是報找不到類的錯誤?」spring

<!--more-->後端

大夥有這樣的疑問,就是由於還沒搞清楚可執行 jar 和普通 jar 到底有什麼區別?今天鬆哥就和你們來聊一聊這個問題。restful

多了一個插件

Spring Boot 中默認打包成的 jar 叫作 可執行 jar,這種 jar 不一樣於普通的 jar,普通的 jar 不能夠經過 java -jar xxx.jar 命令執行,普通的 jar 主要是被其餘應用依賴,Spring Boot 打成的 jar 能夠執行,可是不能夠被其餘的應用所依賴,即便強制依賴,也沒法獲取裏邊的類。可是可執行 jar 並非 Spring Boot 獨有的,Java 工程自己就能夠打包成可執行 jar 。前後端分離

有的小夥伴可能就有疑問了,既然一樣是執行 mvn package 命令進行項目打包,爲何 Spring Boot 項目就打成了可執行 jar ,而普通項目則打包成了不可執行 jar 呢?maven

這咱們就不得不提 Spring Boot 項目中一個默認的插件配置 spring-boot-maven-plugin ,這個打包插件存在 5 個方面的功能,從插件命令就能夠看出:spring-boot

五個功能分別是:微服務

  • build-info:生成項目的構建信息文件 build-info.properties
  • repackage:這個是默認 goal,在 mvn package 執行以後,這個命令再次打包生成可執行的 jar,同時將 mvn package 生成的 jar 重命名爲 *.origin
  • run:這個能夠用來運行 Spring Boot 應用
  • start:這個在 mvn integration-test 階段,進行 Spring Boot 應用生命週期的管理
  • stop:這個在 mvn integration-test 階段,進行 Spring Boot 應用生命週期的管理

這裏功能,默認狀況下使用就是 repackage 功能,其餘功能要使用,則須要開發者顯式配置。ui

打包

repackage 功能的 做用,就是在打包的時候,多作一點額外的事情:spa

  1. 首先 mvn package 命令 對項目進行打包,打成一個 jar,這個 jar 就是一個普通的 jar,能夠被其餘項目依賴,可是不能夠被執行
  2. repackage 命令,對第一步 打包成的 jar 進行再次打包,將之打成一個 可執行 jar ,經過將第一步打成的 jar 重命名爲 *.original 文件

舉個例子:

對任意一個 Spring Boot 項目進行打包,能夠執行 mvn package 命令,也能夠直接在 IDEA 中點擊 package ,以下 :

打包成功以後, target 中的文件以下:

這裏有兩個文件,第一個 restful-0.0.1-SNAPSHOT.jar 表示打包成的可執行 jar ,第二個 restful-0.0.1-SNAPSHOT.jar.original 則是在打包過程當中 ,被重命名的 jar,這是一個不可執行 jar,可是能夠被其餘項目依賴的 jar。經過對這兩個文件的解壓,咱們能夠看出這二者之間的差別。

兩種 jar 的比較

可執行 jar 解壓以後,目錄以下:

能夠看到,可執行 jar 中,咱們本身的代碼是存在 於 BOOT-INF/classes/ 目錄下,另外,還有一個 META-INF 的目錄,該目錄下有一個 MANIFEST.MF 文件,打開該文件,內容以下:

Manifest-Version: 1.0
Implementation-Title: restful
Implementation-Version: 0.0.1-SNAPSHOT
Start-Class: org.javaboy.restful.RestfulApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Build-Jdk-Spec: 1.8
Spring-Boot-Version: 2.1.6.RELEASE
Created-By: Maven Archiver 3.4.0
Main-Class: org.springframework.boot.loader.JarLauncher

能夠看到,這裏定義了一個 Start-Class,這就是可執行 jar 的入口類,Spring-Boot-Classes 表示咱們本身代碼編譯後的位置,Spring-Boot-Lib 則表示項目依賴的 jar 的位置。

換句話說,若是本身要打一個可執行 jar 包的話,除了添加相關依賴以外,還須要配置 META-INF/MANIFEST.MF 文件。

這是可執行 jar 的結構,那麼不可執行 jar 的結構呢?

咱們首先將默認的後綴 .original 除去,而後給文件重命名,重命名完成,進行解壓:

解壓後能夠看到,不可執行 jar 根目錄就至關於咱們的 classpath,解壓以後,直接就能看到咱們的代碼,它也有 META-INF/MANIFEST.MF 文件,可是文件中沒有定義啓動類等。

Manifest-Version: 1.0
Implementation-Title: restful
Implementation-Version: 0.0.1-SNAPSHOT
Build-Jdk-Spec: 1.8
Created-By: Maven Archiver 3.4.0

注意

這個不能夠執行 jar 也沒有將項目的依賴打包進來。

從這裏咱們就能夠看出,兩個 jar ,雖然都是 jar 包,可是內部結構是徹底不一樣的,所以一個能夠直接執行,另外一個則能夠被其餘項目依賴。

一次打包兩個 jar

通常來講,Spring Boot 直接打包成可執行 jar 就能夠了,不建議將 Spring Boot 做爲普通的 jar 被其餘的項目所依賴。若是有這種需求,建議將被依賴的部分,單獨抽出來作一個普通的 Maven 項目,而後在 Spring Boot 中引用這個 Maven 項目。

若是非要將 Spring Boot 打包成一個普通 jar 被其餘項目依賴,技術上來講,也是能夠的,給 spring-boot-maven-plugin 插件添加以下配置:

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

配置的 classifier 表示可執行 jar 的名字,配置了這個以後,在插件執行 repackage 命令時,就不會給 mvn package 所打成的 jar 重命名了,因此,打包後的 jar 以下:

第一個 jar 表示能夠被其餘項目依賴的 jar ,第二個 jar 則表示一個可執行 jar。

好了,關於 Spring Boot 中 jar 的問題,咱們就說這麼多,有問題歡迎留言討論。

關注公衆號【江南一點雨】,專一於 Spring Boot+微服務以及先後端分離等全棧技術,按期視頻教程分享,關注後回覆 Java ,領取鬆哥爲你精心準備的 Java 乾貨!

相關文章
相關標籤/搜索