解讀maven項(xiàng)目的打包方式
前言
現(xiàn)在都是使用idea中maven插件來(lái)打包項(xiàng)目,因此此文章將基于idea中的maven插件打包。
概念
打包分為小包和大包兩種概念:
- 小包:只打包我們寫的代碼,不打包代碼依賴的其他jar包。
- 大包:打包項(xiàng)目本身的代碼以及項(xiàng)目所依賴的其他jar包。
因此,如果我們的項(xiàng)目代碼只需要被別的代碼引用,也就是不需要啟動(dòng)類去運(yùn)行,那么打包成小包即可,如果我們的項(xiàng)目需要獨(dú)立的運(yùn)行,需要啟動(dòng)類去運(yùn)行,那么就需要打包成大包。
準(zhǔn)備
我們先創(chuàng)建一個(gè)maven項(xiàng)目,創(chuàng)建一個(gè)啟動(dòng)類,隨便引入一個(gè)其他依賴。
啟動(dòng)類
pom文件
打包方式
idea自帶的maven工具
首先使用idea中自帶的maven工具打包,idea的maven工具也能打大包和小包。
小包打包第一種方式
小包打包直接運(yùn)行maven中的package即可。
可以看到target目錄下生成了jar包
查看生成的jar包
可以看到只有我們項(xiàng)目的代碼,引入的依賴并沒有被一起打包
這里也就不測(cè)試能不能通過命令java -jar *.jar 去運(yùn)行jar包了,因?yàn)檫@是小包,根據(jù)小包的作用,我們是并不需要去運(yùn)行。
這里我可以告訴你,并不能運(yùn)行,因?yàn)槲覀兇虬臅r(shí)候并沒有去指定啟動(dòng)類的路徑,也就是在META-INF目錄下的MANIFEST.MF文件中指定啟動(dòng)類。
小包打包第二種方式
大包打包我們是需要指定啟動(dòng)類并且將其他依賴一起打包的。
配置打包信息
配置完后,我們可以看到引入的依賴也在被打包的范圍,同時(shí)如果我們不想打包某個(gè)jar包進(jìn)來(lái),可以在此面板選擇刪除,這樣就不會(huì)一同被打包了。
然后去編譯打包
可以看到生成了out輸出文件夾,并且引入的依賴也一同被打包到同個(gè)目錄下了,但是還是沒有合并成同一個(gè)jar,如果要運(yùn)行的話,必須將依賴的jar放在同一個(gè)目錄中才能正常運(yùn)行。
我們來(lái)查看以下生成的jar包
我們發(fā)現(xiàn),打包的jar貌似比小包更簡(jiǎn)潔 ,而且也只有我們本身的java代碼,沒有MANIFTEST文件,沒有的話肯定是無(wú)法運(yùn)行的,因?yàn)槔锩嬗涗泦?dòng)類的路徑以及依賴jar包的存放路徑。
很奇怪,我們的MANIFEST文件跑到這里了,并沒有被一同打包。
可以看到MANIFEST中已經(jīng)生成了jar的存放路徑和啟動(dòng)類的路徑
原來(lái),我們的這種打包方式必須要和打包插件共同使用,后面會(huì)介紹幾種打包插件。
這樣的打包方式也有解決方法,就是將我們打包的jar解壓,將MANIFEST文件放進(jìn)去再壓縮,最后將壓縮好的jar包和引入的jar包放在同一個(gè)目錄中即可運(yùn)行。
小包總結(jié)
從 上面的兩種方式可以看出來(lái),idea自帶的打包方式,只能打包成小包,源碼的部分只有項(xiàng)目本身的代碼。這種 Jar 包就是所謂的 “小包”。
大包打包
從前面來(lái)看,打包打包需要使用到第三方插件,以下來(lái)介紹一些第三方的打包插件。
maven-compiler-plugin
maven-compiler-plugin是一個(gè)Maven插件,可以用來(lái)指定項(xiàng)目源碼的 jdk 版本,編譯后的 jdk 版本,以及編碼格式。
單獨(dú)的使用并不會(huì)打包成大包,還是會(huì)打成小包,因此一般用來(lái)與其他第三方的打包插件聯(lián)合使用。
依賴配置
<build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <!-- 指定maven編譯的jdk版本,如果不指定,maven3默認(rèn)用jdk 1.5 maven2默認(rèn)用jdk1.3 --> <source>1.8</source> <!-- 源代碼使用的JDK版本 --> <target>1.8</target> <!-- 需要生成的目標(biāo)class文件的編譯版本 --> <encoding>UTF-8</encoding><!-- 字符集編碼 --> </configuration> </plugin> </plugins> </build>
打包測(cè)試
效果
可以看到只有源碼被打包而已。
maven-jar-plugin 和 maven-dependency-plugin
這兩個(gè)插件是一起使用的,首先是不推薦使用這種,此種打包方式有一個(gè)比較明顯的缺點(diǎn):打包后會(huì)在 target
目錄下生成 lib
目錄(存放依賴 Jar)和項(xiàng)目 Jar。
也就是說(shuō)由于依賴都存在于 lib
目錄中,所以要想運(yùn)行 Jar 包,必須將 Jar 包和 lib
目錄放在同一個(gè)路徑下。
maven-jar-plugin
首先說(shuō) maven-jar-plugin
插件,它的思想就是:指定啟動(dòng)類、指定依賴包相對(duì)于項(xiàng)目最終 Jar 包所在的路徑、給 MANIFEST.MF
文件添加 Class-Path
屬性(運(yùn)行項(xiàng)目 Jar 包時(shí)會(huì)根據(jù) Class-Path
屬性來(lái)找到其他依賴 Jar 包的路徑),因此這個(gè)插件就是個(gè)配置 MANIFEST.MF
文件的插件。
maven-dependency-plugin
這個(gè)插件才是打包項(xiàng)目的其他依賴,因此這個(gè)必須配合上面的插件使用,兩者缺一不可。
依賴配置
<build> <!-- 項(xiàng)目最終打包成的名字 --> <finalName>community</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <!-- 會(huì)在 MANIFEST.MF 中生成 Class-Path 項(xiàng) --> <!-- 系統(tǒng)會(huì)根據(jù) Class-Path 項(xiàng)配置的路徑加載依賴 --> <addClasspath>true</addClasspath> <!-- 指定依賴包所在目錄,相對(duì)于項(xiàng)目最終 Jar 包的路徑 --> <classpathPrefix>lib/</classpathPrefix> <!-- 指定 MainClass --> <mainClass>com.ronz.community.CommunityApplication</mainClass> </manifest> </archive> </configuration> </plugin> <!-- 配置依賴包 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <!-- 相當(dāng)于執(zhí)行 mvn 命令,將依賴打包到指定目錄 --> <executions> <execution> <id>copy-dependencies</id> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <!--將依賴打包至 target 下的 lib 目錄--> <outputDirectory>${project.build.directory}/lib</outputDirectory> </configuration> </execution> </executions> </plugin> </plugins> </build>
效果
所以說(shuō)想要運(yùn)行項(xiàng)目,必須將lib和源碼jar包放在同一個(gè)目錄下才行,這樣顯然是不太方便的。
maven-assembly-plugin
使用 maven-assembly-plugin
插件打出來(lái)的包只有一個(gè) Jar 包,這個(gè) Jar 包中包含了項(xiàng)目代碼以及依賴的代碼。
也就意味著此種方式打出來(lái)的 Jar 包可以直接通過 java -jar xxx.jar
的命令來(lái)運(yùn)行。
而且我們可以聯(lián)合maven-compiler-plugin插件來(lái)使用。
缺點(diǎn)
maven-assembly-plugin 同名類覆蓋時(shí)會(huì)出現(xiàn)問題。
依賴配置
<build> <!-- 項(xiàng)目最終打包成的名字 --> <finalName>test</finalName> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <!-- 指定maven編譯的jdk版本,如果不指定,maven3默認(rèn)用jdk 1.5 maven2默認(rèn)用jdk1.3 --> <source>1.8</source> <!-- 源代碼使用的JDK版本 --> <target>1.8</target> <!-- 需要生成的目標(biāo)class文件的編譯版本 --> <encoding>UTF-8</encoding><!-- 字符集編碼 --> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <configuration> <archive> <!-- 指定啟動(dòng)類 --> <manifest> <mainClass>com.cw.HelloStart</mainClass> </manifest> </archive> <!-- 描述后綴 --> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> <!-- 相當(dāng)于在執(zhí)行 package 打包時(shí),在后面加上 assembly:single --> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
效果
兩者的區(qū)別
test-jar-with-dependencies.jar
test.jar
明顯可以看到test-jar-with-dependencies.jar才是我們需要的。
maven-shade-plugin
根據(jù) Maven 的官方文檔介紹,maven-shade-plugin
是一個(gè)強(qiáng)大的打包插件。它同樣可以將項(xiàng)目的依賴以及項(xiàng)目的源碼打包成一個(gè)可執(zhí)行 Jar 包。
依賴配置
<build> <!-- 項(xiàng)目最終打包成的名字 --> <finalName>test</finalName> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <!-- 指定maven編譯的jdk版本,如果不指定,maven3默認(rèn)用jdk 1.5 maven2默認(rèn)用jdk1.3 --> <source>1.8</source> <!-- 源代碼使用的JDK版本 --> <target>1.8</target> <!-- 需要生成的目標(biāo)class文件的編譯版本 --> <encoding>UTF-8</encoding><!-- 字符集編碼 --> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <!-- 指定啟動(dòng)類 --> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.cw.HelloStart</mainClass> </transformer> <!-- 下面的配置僅針對(duì)存在同名資源文件的情況,如沒有則不用配置--> <!-- 有些項(xiàng)目包可能會(huì)包含同文件名的資源文件(例如屬性文件)--> <!-- 為避免覆蓋,可以將它們的內(nèi)容合并到一個(gè)文件中 --> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.handlers</resource> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.schemas</resource> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build>
效果
兩種第三方插件打包方式的總結(jié)
使用第二種方式的 assembly
打包出來(lái)的 Jar 包多多少少有些問題,但是使用第三種方式打包出來(lái)的 Jar 包一般都是可用的。所以在將項(xiàng)目打包為大包時(shí),還是推薦使用第三種打包的方式。
如果是大數(shù)據(jù)項(xiàng)目中,我們?nèi)粘J褂帽容^多的是maven-assembly-plugin
插件,例如:大數(shù)據(jù)項(xiàng)目中往往有很多shell
腳本、SQL
腳本、.properties
及.xml
配置項(xiàng)等,采用assembly
插件可以讓輸出的結(jié)構(gòu)清晰而標(biāo)準(zhǔn)化。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java中List<對(duì)象>如何根據(jù)對(duì)象的一個(gè)屬性進(jìn)行去重
這篇文章主要給大家介紹了關(guān)于java中List<對(duì)象>如何根據(jù)對(duì)象的一個(gè)屬性進(jìn)行去重的相關(guān)資料,在開發(fā)中可能會(huì)遇到很多需要去重的情況,比如Person對(duì)象有name跟age兩個(gè)屬性,需要根據(jù)age進(jìn)行去重,需要的朋友可以參考下2023-08-08Object類toString()和equals()方法使用解析
這篇文章主要介紹了Object類toString()和equals()方法使用解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02Java線程中斷及線程中斷的幾種使用場(chǎng)景小結(jié)
在并發(fā)編程中,合理使用線程中斷機(jī)制可以提高程序的魯棒性和可維護(hù)性,本文主要介紹了Java線程中斷及線程中斷的幾種使用場(chǎng)景小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01SpringBoot多環(huán)境切換的配置實(shí)現(xiàn)
在日常的開發(fā)中,一般都會(huì)分好幾種環(huán)境,本文就來(lái)介紹一下SpringBoot多環(huán)境切換的配置實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03mybatis攔截器實(shí)現(xiàn)數(shù)據(jù)權(quán)限項(xiàng)目實(shí)踐
本文主要介紹了mybatis攔截器實(shí)現(xiàn)數(shù)據(jù)權(quán)限項(xiàng)目實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06Java 8系列之Stream中萬(wàn)能的reduce用法說(shuō)明
這篇文章主要介紹了Java 8系列之Stream中萬(wàn)能的reduce用法說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2020-08-08SpringBoot中處理跨域請(qǐng)求CORS的全面指南
跨域資源共享是一種安全機(jī)制,它允許Web應(yīng)用程序在一個(gè)域上的資源請(qǐng)求另一個(gè)域上的資源,下面就跟隨小編一起來(lái)深入了解下SpringBoot中處理跨域請(qǐng)求CORS的具體操作吧2025-04-04解決Aop @AfterReturning因返回類型不一致導(dǎo)致無(wú)法執(zhí)行切面代碼
這篇文章主要介紹了解決Aop @AfterReturning因返回類型不一致導(dǎo)致無(wú)法執(zhí)行切面代碼問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07