Maven打包SpringBoot項(xiàng)目,排除第三方依賴包

一、緣起

image.png

看了朱老大的微博,這不說的正是我嘛!日常開發(fā)部署的過程中,我也會(huì)自己探索引入一些maven的自動(dòng)化部署,但是,到了關(guān)鍵性的上傳服務(wù)器這一步,確實(shí)沒有再精進(jìn)一步。在項(xiàng)目依賴越多越多的情況下,打包上傳確實(shí)是一件費(fèi)時(shí)的事情。所以,按照朱老大的思路,我也嘗試給我的項(xiàng)目包瘦瘦身。

二、運(yùn)行環(huán)境

操作系統(tǒng):Windows 10 ;
開發(fā)工具:IDEA-2019.3;
Web服務(wù)器:Tomcat 9.0.24;
JDK版本: jdk 1.8.0_221;
Maven版本:apache-maven-3.6.1
Spring boot 版本:2.0.9.RELEASE

三、原理分析

工欲善其事,必先利其器。想要把功能做好,就要先明白背后的原理。原理理解清楚了,實(shí)際操作可謂是手到擒來。

1. maven打包spring boot項(xiàng)目,配置pom.xml,將第三方的依賴包排除在項(xiàng)目包之外。
2. 首次打包之后,把項(xiàng)目包上傳到服務(wù)器,同時(shí)也要把第三方依賴包上傳到服務(wù)器。

以后部署的時(shí)候,第三方依賴包沒有發(fā)生變化得話,就不用再次上傳了。要想實(shí)現(xiàn)這樣一個(gè)目的,就像調(diào)整pom.xml中相關(guān)配置<skip>false</skip>。

3. 在服務(wù)器運(yùn)行項(xiàng)目包,要配置項(xiàng)目包引用到第三方依賴包。
  1. 打成jar包的話,這里也可以由兩種方式。第一種,就是在pom.xml中配置了第三方包的依賴的位置,在部署運(yùn)行的時(shí)候,項(xiàng)目包自己會(huì)找到第三方依賴包的位置,這和以前的部署方式?jīng)]有兩樣;第二種,是利用如下命令參數(shù)java -Dloader.path=lib/ -Dfile.encoding=utf-8 -jar abc-api-1.0.0-SNAPSHOT-exec.jar。其中,loader.path參看官方文檔:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#executable-jar-launching。其中,有解釋是這樣的:loader.path can contain directories (which are scanned recursively for jar and zip files), archive paths, a directory within an archive that is scanned for jar files (for example, dependencies.jar!/lib), or wildcard patterns (for the default JVM behavior). Archive paths can be relative to loader.home or anywhere in the file system with a jar:file: prefix.。大概的意思就是:配置了這個(gè)參數(shù)的目錄,運(yùn)行項(xiàng)目包的時(shí)候,就會(huì)去掃描該目錄下的第三方依賴包。
    看了這么多,我的感觸就是,知識(shí)太過龐雜了。就拿這個(gè)參數(shù)來說,這個(gè)知識(shí)點(diǎn)可能是jdk里的,也可以說spring boot里的。但是,在此之前,我還是不確定的。再說,中文互聯(lián)網(wǎng)的內(nèi)容太過雜亂,搜索尋找起來就格外的費(fèi)力。
  2. 打成war的話,我們可以把第三方依賴包放到tomcat的/lib目錄中,這樣,項(xiàng)目就可以自動(dòng)找到了。但是,/lib目錄下面本來就有許多自帶的jar包了,為了防止混淆,可以在/lib目錄下建一個(gè)ext目錄,來將項(xiàng)目要用到的第三方依賴包放在此處。
    但是tomcat是無法識(shí)別這個(gè)ext目錄里面的jar包的,此時(shí)需要修改tomcat配置文件${catalina.home}/conf/catalina.properties中的 common.loader值,加上${catalina.home}/lib/ext/*.jar,完成此步驟后,項(xiàng)目啟動(dòng)便可以使用到lib/ext里面的jar包了。

四、實(shí)際操作

1.jar包方式打包

  1. pom.xml 中的配置如下,里面詳細(xì)解釋了配置的含義。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.keqing</groupId>
    <artifactId>kafka3</artifactId>
    <version>0.0.1</version>
    <name>kafka3</name>
    <packaging>jar</packaging>
  
    <build>
        <plugins>
            
            <!--
                官方解釋:These are miscellaneous tools available through Maven by default.
                Dependency manipulation (copy, unpack) and analysis.
                這個(gè)插件的作用:把第三方依賴包復(fù)制到target/lib/目錄下,達(dá)到分離的目的。
            -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <!-- 復(fù)制第三方 jar 到項(xiàng)目目錄下的 target/lib/ 下 -->
                    <execution>
                        <goals>
                            <!--
                             takes the list of project direct dependencies and optionally transitive
                             dependencies and copies them to a specified location, stripping the version
                             if desired.
                             This goal can also be run from the command line.
                            -->
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
                            <excludeScope>provided</excludeScope>
                            <!-- 配置的作用:跳過復(fù)制第三方依賴這一步。這是在首次上傳
                                  第三方依賴到服務(wù)器之后,啟用這個(gè)選項(xiàng),可以不用在打包時(shí)
                                  重復(fù)復(fù)制,節(jié)省時(shí)間。-->
                            <skip>false</skip>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <!--
                官方解釋:These plugins relate to packaging respective artifact types.
                Build a JAR from the current project.
                這個(gè)插件的作用:把項(xiàng)目打成jar包,插件配置的意思是:把第三方依賴的路徑,
                寫入到MANIFEST.MF 文件中,格式是./lib/xxx.jar。這樣做,就是 讓項(xiàng)目包在
                運(yùn)行的時(shí)候,能夠像以前一樣找到第三方依賴包。
            -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <!-- 指定 Spring Boot 啟動(dòng)類,實(shí)際測(cè)試中必須 -->
<!--                            <mainClass>com.keqing.Kafka3Application</mainClass>-->
                            <!-- 將所有第三方 jar 添加到項(xiàng)目 jar 的 MANIFEST.MF 文件中,這樣運(yùn)行 jar 時(shí)依賴包才能 
                                   被加載 。此為關(guān)鍵步驟,有了這一步,我們?cè)诎训谌揭蕾嚢c項(xiàng)目包分離的情況 
                                   下,在服務(wù)器運(yùn)行,就和沒有分離時(shí), 是一摸一樣的了。-->
                            <addClasspath>true</addClasspath>
                            <!-- 指定第三方 jar 的目標(biāo)目錄為 ./lib/-->
                            <classpathPrefix>./lib/</classpathPrefix>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <!--
                上面的插件,只是把項(xiàng)目包打成符合maven的標(biāo)準(zhǔn)格式,還有利用spring boot的插件,
                把包打成符合spring boot的格式才行。
                官方文檔:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/
                為了讓用戶方便使用 Maven,少進(jìn)行配置甚至不用配置,就需要用 Maven 構(gòu)建項(xiàng)目。Maven 在安      
                裝好后,自動(dòng)為生命周期的主要階段綁定很多插件的目標(biāo)。
            -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <!-- repackage 時(shí)排除掉 第三方依賴 jar 文件,我們的可運(yùn)行 Spring Boot 的 jar 文件瞬間變小 ^_^
                下面的配置給出了怎樣將生命周期的階段與插件的目標(biāo)相互綁定。這樣,在執(zhí)行mvn命令時(shí),會(huì)自 
                動(dòng)執(zhí)行 這個(gè)插件的目標(biāo)。
                目標(biāo)可以有一個(gè)默認(rèn)的階段綁定,我們將在下面討論。
                目標(biāo)有一個(gè)默認(rèn)的階段綁定,然后它將在該階段執(zhí)行。但是,如果目標(biāo)沒有綁定到任何生命周期階 
                段, 那么它就不會(huì)在構(gòu)建生命周期中執(zhí)行。
                官方文檔:https://maven.apache.org/guides/mini/guide-configuring-plugins.html
                -->
<!--                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>-->
                <!--配置重新打包時(shí),要包含的第三方依賴包,配置為nothing,那么就會(huì)排除掉所有的第三方依賴 
                    包-->
                <configuration>
                    <includes>
                        <include>
                            <groupId>nothing</groupId>
                            <artifactId>nothing</artifactId>
                        </include>
                    </includes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2.war包方式打包

1.pom.xml配置如下,里面一樣又詳細(xì)的說明

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.keqing</groupId>
    <artifactId>kafka3</artifactId>
    <version>0.0.1</version>
    <name>kafka3</name>
    <!--要按照war包格式打包,就要修改這里的配置-->
    <packaging>war</packaging>
    <build>
        <finalName>kafka</finalName>
        <plugins>
            <!--此插件的配置沒有改變。唯一需要變得是,在首次打包,并上傳了第三方依賴包之后,
            就可以將<skip>設(shè)置為true了。這樣可以跳過復(fù)制,節(jié)省時(shí)間。-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
                            <excludeScope>provided</excludeScope>
                            <skip>false</skip>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <!--這里修改為war包插件。war包的配置,要在此處排除掉第三方依賴包。而打jar包時(shí),標(biāo)準(zhǔn)流程 
                里,打jar包,并不會(huì)包含第三方依賴的包,第三方依賴包是在spring-boot-maven-plugin運(yùn)行時(shí),          
                被引入到項(xiàng)目jar包中的。-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <configuration>
                    <packagingExcludes>
                        WEB-INF/lib/*.jar
                    </packagingExcludes>
                </configuration>
            </plugin>
           <!--此插件配置依然相同,依舊要把第三方依賴排除出去。-->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <includes>
                        <include>
                            <groupId>nothing</groupId>
                            <artifactId>nothing</artifactId>
                        </include>
                    </includes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

五、總結(jié)

寫這篇小文,真是煞費(fèi)苦心。難在哪里呢?難在涉及的知識(shí)太過龐雜。比如,有關(guān)maven的占位符問題,這個(gè)本來就是我的一個(gè)知識(shí)盲點(diǎn),在看到很多地方用到這方面的配置,并且又和spring boot交織在一塊的時(shí)候,我更是一腦袋的漿糊了。所以,關(guān)于這個(gè)知識(shí)點(diǎn),我還要另起一文,專門來闡述。
比如,有關(guān)java命令行的使用。有關(guān)maven插件的使用和配置,maven插件運(yùn)行的原理,有關(guān)spring boot打包的原理,spring boot打成的包的結(jié)構(gòu)特點(diǎn),springboot打成的包的運(yùn)行原理,tocmat的目錄結(jié)構(gòu)的含義。
其實(shí),看起來很多,但是,都是基礎(chǔ)性知識(shí)的復(fù)雜運(yùn)用。也說明自身基礎(chǔ)知識(shí)掌握的不夠牢靠。
尤其,對(duì)于maven 還是一知半解。然后,spring boot 又是基于maven的。在maven的基礎(chǔ)上,又對(duì)maven做了擴(kuò)展配置。讓問題一下子變得更加復(fù)雜了。我也感受到spring boot 知識(shí)的龐雜。僅僅是官方文檔,里面就有我需要的很多很多的答案。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容