Maven 各類花式構建,不用 SpringBoot 也能打出可執行 Jar 包

先點贊再看,養成好習慣

Spring Boot 的打包插件用着很爽吧,直接把源碼和全部依賴打成一個 Jar 包還能直接java -jar運行。那若是非 Spring Boot 項目,想打成一個可執行的 Jar 包該怎麼辦呢?html

別慌,Maven 這種老牌構建工具,搞定這個事情還不是輕輕鬆鬆!
java

下面介紹一些其餘的 Maven 插件,一樣能夠直接將 Maven 項目打包成一個可執行的 Jar 包(uber jar/executable jar),並且功能更強大,應用場景更豐富!
git

關於這個 uber jar/executable jar 的名稱由來,能夠參考我以前的一篇文章《Executable Jar/Uber Jar/Shade Jar/Shadow Jar/Fat Jar 究竟是什麼東西?》github

maven-dependency-plugin

maven-dependency-plugin是 Maven 的一個內置插件,從名字就能看出來,它的功能就是處理依賴的。內置了不少目標(goals),功能很是全:spring

  • dependency:copydependency:copy-dependencies
  • dependency:unpack
  • dependency:unpack-dependencies
  • dependency:resolve
  • dependency:sources
  • dependency:resolve-plugins
  • dependency:go-offline
  • dependency:purge-local-repository
  • dependency:analyze
  • dependency:analyze-dep-mgt
  • dependency:analyze-report
  • dependency:tree
  • dependency:build-classpath
  • dependency:list-repositories
  • dependency:get

經過 unpack-dependencies 這個目標來解壓依賴的包/源碼,就能夠完成一個 all-in-one 的打包方式:apache

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-dependency-plugin</artifactId>
  <executions>

    <execution>
      <id>unpack-dependencies</id>
      <!-- 綁定到 prepare-package 階段 -->
      <phase>prepare-package</phase>
      <goals>
        <goal>unpack-dependencies</goal>
      </goals>
      <configuration>
        <includeScope>runtime</includeScope>
        <outputDirectory>${project.build.outputDirectory}</outputDirectory>
      </configuration>
    </execution>
  </executions>
</plugin>

這個 unpack 的方式,會把全部依賴包(內部模塊依賴和外部模塊依賴)都「解壓」,就是說會把依賴包的代碼(class)都拷貝到 outputDirectory 目錄裏,相似一個合併的操做,結果就像這樣:
image.png
而後再給 Jar 指定一個 main-class 讓他直接可執行:segmentfault

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-jar-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <mainClass>
          com.github.kongwu.mavenbuild.BuildExample
        </mainClass>
      </manifest>
    </archive>
  </configuration>
</plugin>

固然!這個插件能幹的事可不止這一種……看看上面的命令就知道,它功能很是多,這裏介紹的只是它的一個小功能。app

maven-shade-plugin

maven-shade-plugin 也是 Maven 內置的一款插件,也能夠直接打一個可執行 Jar 出來。和 dependency 插件效果同樣,也是「解壓」的模式,將全部依賴包的 class 放在一塊兒,配置一個 transformer 和 mainClass 就行:maven

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <executions>
    <execution>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <shadedArtifactAttached>true</shadedArtifactAttached>
        <transformers>
          <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <mainClass>com.github.kongwu.mavenbuild.BuildExample</mainClass>
          </transformer>
        </transformers>
      </configuration>
    </execution>
  </executions>
</plugin>

構建後的默認 jar 文件爲:${artifactId}-${version}-shaded.jar,不喜歡的話你也能夠經過<outputFile>去修改輸出的 jar 文件spring-boot

這個插件的精髓在 shade ,而這個「解壓」只是基本的功能。

有沒有以爲這個插件名字很奇怪,shade是什麼意思?

shade機翻爲陰影、遮蔽,shade jar 是指將 jar 包及其依賴包打包到一個 jar 文件內,同時提供 shade「遮蔽 / 重命名」 某些依賴包的功能

關於 shade 的詳細解釋,能夠參考個人另外一篇文章《Shade Jar/Shadow Jar 的解釋》

maven-assembly-plugin

最後介紹的這個 maven-assembly-plugin 插件,算是 maven 裏最強的構建插件了,雖然它有用的 goal 只有一個,但功能真的很是很是強大:

  1. 能夠經過獨立的描述文件配置詳細的構建規則
  2. 包含或者排除某個模塊/目錄/文件
  3. 支持 maven filter
  4. 一套代碼,同時構建多個不一樣配置的 bin 包
  5. 不一樣的構建包格式,好比 jar/zip/tar/gz 等等
  6. ……

好比 Zookeeper/Nacos/Arthas/Jenkins ,或者最近比較火的 pulsar 之類須要獨立運行的軟件,不少都是用這個插件構建的

先看它的一個簡單場景,構建一個可執行 Jar 包:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
      <configuration>
        <archive>
          <manifest>
            <mainClass>
              com.github.kongwu.mavenbuild.BuildExample
            </mainClass>
          </manifest>
        </archive>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
      </configuration>
    </execution>
  </executions>
</plugin>

和上面兩個插件效果同樣,都是「解壓」的方式,默認構建的文件爲 ${artifactId}-${version}-jar-with-dependencies.jar

這麼強大的插件,只拿他構建一個 uber jar 可有點太浪費了,若是隻是簡單的 uber jar 場景,用前面兩種方式就足夠了。

因此這個插件更適合複雜的構建需求,簡單的uber jar場景拿這種加特林級別的工具備一點浪費了……

來看看 Nacos 中的使用方式:
image.png
在 Nacos 的源碼中,單獨放了一個 distribution 的模塊用於構建,藉助 assembly 插件 + profile 功能,能夠很方便的構建出各類環境的 bin 包:

<!-- nacos distribution/pom.xml-->

<profile>
  <id>release-nacos</id>
  <dependencies>
    <dependency>
      <groupId>${project.groupId}</groupId>
      <artifactId>nacos-console</artifactId>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptors>
            <descriptor>release-nacos.xml</descriptor>
          </descriptors>
          <tarLongFileMode>posix</tarLongFileMode>
        </configuration>
        <executions>
          <execution>
            <id>make-assembly</id>
            <phase>install</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
    <finalName>nacos</finalName>
  </build>
</profile>

 <profile>
   <id>release-core</id>
   <dependencies>
     <dependency>
       <groupId>${project.groupId}</groupId>
       <artifactId>nacos-core</artifactId>
     </dependency>
   </dependencies>
   <build>
     <plugins>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-assembly-plugin</artifactId>
         <executions>
           <execution>
             <id>release-core</id>
             <goals>
               <goal>single</goal>
             </goals>
             <phase>package</phase>
             <configuration>
               <descriptors>
                 <descriptor>release-core.xml</descriptor>
               </descriptors>
               <appendAssemblyId>false</appendAssemblyId>
             </configuration>
           </execution>
         </executions>
       </plugin>
     </plugins>
     <finalName>nacos-core</finalName>
   </build>
</profile>

Nacos 這種構建方式,也是比較「主流」的方式了,若是哪天你有構建獨立運行包的需求,相信你也會用這種方式。

總結

完整代碼放在https://github.com/kongwu-/maven-build-examples/blob/master/pom.xml ,有興趣的小夥伴能夠拉下來試試

好了,介紹完了這幾種插件構建 uber-jar 的玩法,如今作個對比:

dependency shade assembly
優勢 goals 豐富,除了 unpack 還有不少其餘的功能,好比清理/查看依賴樹等等 專爲 uber-jar 而生,並且支持 shade 功能,若是有重定位的需求,只能選它 功能最強,配置很是靈活,但沒有 shade 功能
缺點 畢竟只是個處理依賴的插件,在構建方面的功能比較弱 複雜的構建需求下,功能會有些不足 沒有 shade 功能,並且配置比較複雜
應用場景 適合簡單的 uber-jar 功能 最適合 uber-jar 的構建,配合 shade 功能簡直完美 適合複雜場景下的構建,不止是 uber jar

本文介紹的 3 種插件,他們在構建 uber jar 的機制上和 Spring Boot 有所不一樣:

Spring Boot 構建插件將會將依賴的 Jar 包打在 uber jar 內,是一種 "jars-in-a-jar" 的方式, 經過它的自定義 ClassLoader 去加載 Jar 包內的 Jar 包;而上面介紹的幾種插件,並不會干預 mainClass 和 ClassLoader ,沒法作到加載 Jar 包內的 Jar 包,因此都是經過「解壓」的方式。

注意,Spring Boot 的構建插件,不僅能用在 Spring Boot 項目中。它的核心功能仍是構建,只是把啓動類換成了 Spring Boot 的,而後經過它自定義的 ClassLoader 來加載。

因此,用spring-boot-maven-plugin將一些非 Spring(Boot) 項目打包成一個 uber jar 也徹底沒問題,JDK 和 Maven 的版本匹配就好。

參考

關於以上幾個插件的詳細功能,能夠參考下面插件的官方文檔,Maven 的文檔仍是比較詳細的:

免費小菜

附上一張本身重繪的 Maven default 生命週期圖,仍是比較清晰的,標明瞭每一個 phase 對應的不一樣 plugin 的不一樣 goal,若有須要自行保存(原圖略大,點擊查看大圖)

maven_lifecycle (5) (1).png

原創不易,禁止未受權的轉載。若是個人文章對您有幫助,就請點贊/收藏/關注鼓勵支持一下吧❤❤❤❤❤❤
相關文章
相關標籤/搜索