美文网首页
Maven打包SpringBoot项目,排除第三方依赖包

Maven打包SpringBoot项目,排除第三方依赖包

作者: _小毛驴 | 来源:发表于2021-03-19 16:55 被阅读0次

    一、缘起

    image.png

    看了朱老大的微博,这不说的正是我嘛!日常开发部署的过程中,我也会自己探索引入一些maven的自动化部署,但是,到了关键性的上传服务器这一步,确实没有再精进一步。在项目依赖越多越多的情况下,打包上传确实是一件费时的事情。所以,按照朱老大的思路,我也尝试给我的项目包瘦瘦身。

    二、运行环境

    操作系统:Windows 10 ;
    开发工具:IDEA-2019.3;
    Web服务器:Tomcat 9.0.24;
    JDK版本: jdk 1.8.0_221;
    Maven版本:apache-maven-3.6.1
    Spring boot 版本:2.0.9.RELEASE

    三、原理分析

    工欲善其事,必先利其器。想要把功能做好,就要先明白背后的原理。原理理解清楚了,实际操作可谓是手到擒来。

    1. maven打包spring boot项目,配置pom.xml,将第三方的依赖包排除在项目包之外。
    2. 首次打包之后,把项目包上传到服务器,同时也要把第三方依赖包上传到服务器。

    以后部署的时候,第三方依赖包没有发生变化得话,就不用再次上传了。要想实现这样一个目的,就像调整pom.xml中相关配置<skip>false</skip>

    3. 在服务器运行项目包,要配置项目包引用到第三方依赖包。
    1. 打成jar包的话,这里也可以由两种方式。第一种,就是在pom.xml中配置了第三方包的依赖的位置,在部署运行的时候,项目包自己会找到第三方依赖包的位置,这和以前的部署方式没有两样;第二种,是利用如下命令参数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.。大概的意思就是:配置了这个参数的目录,运行项目包的时候,就会去扫描该目录下的第三方依赖包。
      看了这么多,我的感触就是,知识太过庞杂了。就拿这个参数来说,这个知识点可能是jdk里的,也可以说spring boot里的。但是,在此之前,我还是不确定的。再说,中文互联网的内容太过杂乱,搜索寻找起来就格外的费力。
    2. 打成war的话,我们可以把第三方依赖包放到tomcat的/lib目录中,这样,项目就可以自动找到了。但是,/lib目录下面本来就有许多自带的jar包了,为了防止混淆,可以在/lib目录下建一个ext目录,来将项目要用到的第三方依赖包放在此处。
      但是tomcat是无法识别这个ext目录里面的jar包的,此时需要修改tomcat配置文件${catalina.home}/conf/catalina.properties中的 common.loader值,加上${catalina.home}/lib/ext/*.jar,完成此步骤后,项目启动便可以使用到lib/ext里面的jar包了。

    四、实际操作

    1.jar包方式打包

    1. pom.xml 中的配置如下,里面详细解释了配置的含义。
    <?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.
                    这个插件的作用:把第三方依赖包复制到target/lib/目录下,达到分离的目的。
                -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-dependency-plugin</artifactId>
                    <executions>
                        <!-- 复制第三方 jar 到项目目录下的 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>
                                <!-- 配置的作用:跳过复制第三方依赖这一步。这是在首次上传
                                      第三方依赖到服务器之后,启用这个选项,可以不用在打包时
                                      重复复制,节省时间。-->
                                <skip>false</skip>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
    
                <!--
                    官方解释:These plugins relate to packaging respective artifact types.
                    Build a JAR from the current project.
                    这个插件的作用:把项目打成jar包,插件配置的意思是:把第三方依赖的路径,
                    写入到MANIFEST.MF 文件中,格式是./lib/xxx.jar。这样做,就是 让项目包在
                    运行的时候,能够像以前一样找到第三方依赖包。
                -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-jar-plugin</artifactId>
                    <configuration>
                        <archive>
                            <manifest>
                                <!-- 指定 Spring Boot 启动类,实际测试中必须 -->
    <!--                            <mainClass>com.keqing.Kafka3Application</mainClass>-->
                                <!-- 将所有第三方 jar 添加到项目 jar 的 MANIFEST.MF 文件中,这样运行 jar 时依赖包才能 
                                       被加载 。此为关键步骤,有了这一步,我们在把第三方依赖包与项目包分离的情况 
                                       下,在服务器运行,就和没有分离时, 是一摸一样的了。-->
                                <addClasspath>true</addClasspath>
                                <!-- 指定第三方 jar 的目标目录为 ./lib/-->
                                <classpathPrefix>./lib/</classpathPrefix>
                            </manifest>
                        </archive>
                    </configuration>
                </plugin>
                <!--
                    上面的插件,只是把项目包打成符合maven的标准格式,还有利用spring boot的插件,
                    把包打成符合spring boot的格式才行。
                    官方文档:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/
                    为了让用户方便使用 Maven,少进行配置甚至不用配置,就需要用 Maven 构建项目。Maven 在安      
                    装好后,自动为生命周期的主要阶段绑定很多插件的目标。
                -->
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <!-- repackage 时排除掉 第三方依赖 jar 文件,我们的可运行 Spring Boot 的 jar 文件瞬间变小 ^_^
                    下面的配置给出了怎样将生命周期的阶段与插件的目标相互绑定。这样,在执行mvn命令时,会自 
                    动执行 这个插件的目标。
                    目标可以有一个默认的阶段绑定,我们将在下面讨论。
                    目标有一个默认的阶段绑定,然后它将在该阶段执行。但是,如果目标没有绑定到任何生命周期阶 
                    段, 那么它就不会在构建生命周期中执行。
                    官方文档:https://maven.apache.org/guides/mini/guide-configuring-plugins.html
                    -->
    <!--                <executions>
                        <execution>
                            <goals>
                                <goal>repackage</goal>
                            </goals>
                        </execution>
                    </executions>-->
                    <!--配置重新打包时,要包含的第三方依赖包,配置为nothing,那么就会排除掉所有的第三方依赖 
                        包-->
                    <configuration>
                        <includes>
                            <include>
                                <groupId>nothing</groupId>
                                <artifactId>nothing</artifactId>
                            </include>
                        </includes>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    

    2.war包方式打包

    1.pom.xml配置如下,里面一样又详细的说明

    <?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>设置为true了。这样可以跳过复制,节省时间。-->
                <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包时,标准流程 
                    里,打jar包,并不会包含第三方依赖的包,第三方依赖包是在spring-boot-maven-plugin运行时,          
                    被引入到项目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>
    
    

    五、总结

    写这篇小文,真是煞费苦心。难在哪里呢?难在涉及的知识太过庞杂。比如,有关maven的占位符问题,这个本来就是我的一个知识盲点,在看到很多地方用到这方面的配置,并且又和spring boot交织在一块的时候,我更是一脑袋的浆糊了。所以,关于这个知识点,我还要另起一文,专门来阐述。
    比如,有关java命令行的使用。有关maven插件的使用和配置,maven插件运行的原理,有关spring boot打包的原理,spring boot打成的包的结构特点,springboot打成的包的运行原理,tocmat的目录结构的含义。
    其实,看起来很多,但是,都是基础性知识的复杂运用。也说明自身基础知识掌握的不够牢靠。
    尤其,对于maven 还是一知半解。然后,spring boot 又是基于maven的。在maven的基础上,又对maven做了扩展配置。让问题一下子变得更加复杂了。我也感受到spring boot 知识的庞杂。仅仅是官方文档,里面就有我需要的很多很多的答案。

    相关文章

      网友评论

          本文标题:Maven打包SpringBoot项目,排除第三方依赖包

          本文链接:https://www.haomeiwen.com/subject/xyfvcltx.html