当前位置: 首页 > news >正文

SpringBoot - 用maven-dependency-plugin插件将项目代码与依赖分开打包

SpringBoot - 用maven-dependency-plugin插件将项目代码与依赖分开打包

写在前面

通常基于SpringBoot框架的项目,在发布打包时会将项目代码和所有依赖文件一起打成一个可执行的、一体化的JAR包,如果项目的依赖包很多,那么这个JAR包就会非常大,如果想把项目依赖的JAR从项目一体化的JAR包中分离出来,该怎么办呢?

具体步骤

①. 修改打包插件

将原来的打包插件:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>2.4.2</version>
    <configuration>
        <executable>true</executable>
        <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
    </configuration>
</plugin>

替换为下面的打包插件:

<!-- 需要指定启动类,否则报错。-->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <!-- 生成的项目JAR包中,不要包含pom.xml和pom.properties这两个文件 -->
            <addMavenDescriptor>false</addMavenDescriptor>
            <manifest>
                <!-- 是否要把第三方依赖的JAR包加入到类构建路径 -->
                <addClasspath>true</addClasspath>
                <!-- 外部依赖JAR包的存放路径,为了在MANIFEST.MF文件中指定外部依赖的路径 -->
                <classpathPrefix>lib/</classpathPrefix>
                <!-- 项目主启动类 -->
                <mainClass>cn.hadoopx.servicex.ServicexApplication</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>
②. 新增文件复制插件
<!-- 复制项目依赖的JAR包到指定的lib目录-->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-lib</id>
            <phase>package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
            	<!-- 将外部依赖的JAR包复制到target/lib路径下 -->
                <outputDirectory>target/lib</outputDirectory>
                <excludeTransitive>false</excludeTransitive>
                <stripVersion>false</stripVersion>
                <includeScope>runtime</includeScope>
            </configuration>
        </execution>
    </executions>
</plugin>
③. 按常规方式打包
④. 将项目JAR和lib目录复制到项目的部署路径下,执行启动命令

在这里插入图片描述

常见问题

①. servicex-test-1.0-SNAPSHOT.jar 中没有主清单属性

由于在打包插件中没有指定项目主启动类导致。

maven-dependency-plugin插件的使用

一、goal

maven-dependency-plugin插件最常用的goal有:copy、copy-dependencies、unpack、unpack-dependencies

copy:拷贝指定jar包到指定目录,与当前工程的依赖没有关系

copy-dependencies:拷贝依赖jar包到指定目录

unpack:解压指定jar包到指定目录,与当前工程的依赖没有关系

unpack-dependencies:解压依赖jar包到指定目录

二、copy

copy可以的配置的项比较多

是必须配置的,指定jar包

默认值${project.build.directory}/dependency

1.pom文件

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>org.example</groupId>
    <artifactId>maven-haha</artifactId>
    <version>1.0-SNAPSHOT</version>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.8</version>
                <configuration>
                    <artifactItems>
                        <artifactItem>
                            <groupId>junit</groupId>
                            <artifactId>junit</artifactId>
                            <version>4.11</version>
                        </artifactItem>
                    </artifactItems>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2.使用dependency:copy

mvn clean dependency:copy

img

结果:

img

三、copy-dependencies

1.pom文件

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>org.example</groupId>
    <artifactId>maven-haha</artifactId>
    <version>1.0-SNAPSHOT</version>
 
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.8</version>
            </plugin>
        </plugins>
    </build>
</project>

2.使用dependency:copy-dependencies

mvn clean dependency:copy-dependencies

img

结果:

img

四、unpack、unpack-dependencies

unpack、unpack-dependencies是解压到指定目录,与copy、copy-dependencies操作类似

spring-boot-maven-plugin 打包分离依赖lib

1. 问题: spring-boot项目,默认生成的pom使用spring-boot-maven-plugin打包,会把所有依赖项都打进jar文件中,在调试阶段需要频繁传输jar包时很痛苦。

先看spring-boot-maven-plugin官文 [https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle ],其中有一节

5.3.5. Dependency Exclusion

By default, both the repackage and the run goals will include any provided dependencies that are defined in the project. A Spring Boot project should consider provided dependencies as “container” dependencies that are required to run the application.

Some of these dependencies may not be required at all and should be excluded from the executable jar. For consistency, they should not be present either when running the application.

There are two ways one can exclude a dependency from being packaged/used at runtime:

  • Exclude a specific artifact identified by groupId and artifactId, optionally with a classifier if needed.
  • Exclude any artifact belonging to a given groupId.

简译: spring-boot-maven-plugin默认会把依赖都打进jar包中,如果要使用exclude排除某项/某些依赖有两种方式:1.指定groupId和artifactId, 2.指定排除groupId下的所有项。这证实了spring-boot-maven-plugin的确会把依赖和程序打在一起。但是如果要用exclude排除所有依赖项的话显然不太容易,枚举所所有groupId的工作量就不小,而且笨重,所以排除。

Collection of artifact definitions to include. The Include element defines mandatory groupId and artifactId properties and an optional mandatory groupId and artifactId properties and an optional classifier property.

要包含的集合。其中的Include属性定义了groupId和artifactId属性…

这里有点不清晰:includes是要包含没错,但它与“默认值”之间是什么关系?spring-boot-maven-plugin插件默认在打包的时候是将所有依赖一并打包到最终文件的(jar或war),那么如果定义了includes,是只采用includes还是所有依赖+includes还是怎样?

经过实验,含义应该是“以includes定义覆盖默认值”,即显式包含了哪些就只有哪些。如此,就可以利用这个属性实现分离依赖的效果:

<!-- 原有自动生成的pom -->
...
<plugin>
    <groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-maven-plugin</artifactId>
	<version>2.4.2</version> 
</plugin>
...
 
<!-- 改成 -->
...
<plugin>
    <groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-maven-plugin</artifactId>
	<version>2.4.2</version>
	<configuration>
		<includes>
            <!-- 这里只包含一个不存在的项nothing,即代表什么都不包含,当然名字可以随便写 -->
			<include>
				<groupId>nothing</groupId>
				<artifactId>nothing</artifactId>
		    </include>
		</includes>
	</configuration>
</plugin>
...

然后再使用maven-dependency-plugin插件把依赖项拷贝到lib文件夹中,最后的pom文件build标签如下:

<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
 
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<version>2.4.2</version>
				<configuration>
					<includes>
						<include>
							<groupId>haha</groupId>
							<artifactId>haha</artifactId>
						</include>
					</includes>
				</configuration>
			</plugin>
 
			<!--拷贝依赖到lib目录-->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-dependency-plugin</artifactId>
				<executions>
					<execution>
						<id>copy-lib</id>
						<phase>package</phase>
						<goals>
							<goal>copy-dependencies</goal>
						</goals>
						<configuration>
							<outputDirectory>target/lib</outputDirectory>
							<excludeTransitive>false</excludeTransitive>
							<stripVersion>false</stripVersion>
							<includeScope>compile</includeScope>
						</configuration>
					</execution>
				</executions>
			</plugin>
 
		</plugins>
</build>

使用maven窗口的package指令打包,target结果如下:

img img

使用java.ext.dirs指定lib路径启动,(我这里使用-Dloader.path没有加载成功)

java -jar -Djava.ext.dirs=lib xxx-0.0.1-SNAPSHOT.jar

注:这里使用java.ext.dirs有一个问题:可能有些java内在的库调用会失败,比如我这里调用到了jce.jar>javax>crypto>Mac>getInstance会失败。参考链接https://blog.csdn.net/w47_csdn/article/details/80254459 中的一段话:

首先介绍下java.ext.dirs参数的使用和环境变量:java中系统属性java.ext.dirs指定的目录由ExtClassLoader加载器加载,如果您的程序没有指定该系统属性(-Djava.ext.dirs=sss/lib)那么该加载器默认加载 J A V A H O M E / l i b / e x t 目录下的所有 j a r 文件。但如果你手动指定系统属性且忘了把 JAVA_HOME/lib/ext目录下的所有jar文件。但如果你手动指定系统属性且忘了把 JAVAHOME/lib/ext目录下的所有jar文件。但如果你手动指定系统属性且忘了把JAVA_HOME/lib/ext路径给加上,那么ExtClassLoader不会去加载$JAVA_HOME/lib/ext下面的jar文件,这意味着你将失去一些功能,例如java自带的加解密算法实现。

修改上述java指令,加上系统默认的ext路径$JAVA_HOME/jre/lib/ext:

java -jar -Djava.ext.dirs=lib:$JAVA_HOME/jre/lib/ext xxx-0.0.1-SNAPSHOT.jar注意冒号做分隔符是linux,可能不同系统不一样

至此,依赖项在不变动的情况下不用重复传输,修改代码重新编译后只需要传输较小的jar包即可。

相关文章:

  • 一文学会如何使用适配器模式
  • 计算机网络原理 谢希仁(第8版)第四章习题答案
  • Linux入门第三天——linux命令(二)
  • 为什么要在单片机程序中使用结构体和指针
  • ROS1云课→19仿真turtlebot(stage)
  • VL1_四选一多路器(完整RTL、Testbench和覆盖率)
  • 【fiddler学习笔记】——安装、原理、使用
  • Idea无法引入@Test 或@Test引入报错【BUG解决】
  • Java中常见包装类型Integer、BigDecimal等特点说明
  • 渗透测试-apt攻击与防御系列-利用WinRAR跨目录获取Net-NTLM Hash和DLL劫持
  • MySQL的多表查询
  • Linux下udev应用
  • Responder的使用
  • 【小月电子】FPGA开发板(XLOGIC_V1)系统学习教程-LESSON6
  • JAVA和JVM和JDK和JRE和JAVA SE 是什么? 他们有什么区别? 怎么区分 编程下哪个?
  • 3.7、@ResponseBody 和 @RestController
  • gitlab-ci配置详解(一)
  • IDEA 插件开发入门教程
  • in typeof instanceof ===这些运算符有什么作用
  • JS创建对象模式及其对象原型链探究(一):Object模式
  • Python3爬取英雄联盟英雄皮肤大图
  • Shell编程
  • VirtualBox 安装过程中出现 Running VMs found 错误的解决过程
  • 面试遇到的一些题
  • 译米田引理
  • 阿里云服务器如何修改远程端口?
  • 曜石科技宣布获得千万级天使轮投资,全方面布局电竞产业链 ...
  • ​​​​​​​​​​​​​​汽车网络信息安全分析方法论
  • ![CDATA[ ]] 是什么东东
  • #微信小程序:微信小程序常见的配置传值
  • (C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切
  • (二)什么是Vite——Vite 和 Webpack 区别(冷启动)
  • (附源码)springboot车辆管理系统 毕业设计 031034
  • (十二)devops持续集成开发——jenkins的全局工具配置之sonar qube环境安装及配置
  • (算法设计与分析)第一章算法概述-习题
  • (五)Python 垃圾回收机制
  • (一)pytest自动化测试框架之生成测试报告(mac系统)
  • (转)3D模板阴影原理
  • (自用)learnOpenGL学习总结-高级OpenGL-抗锯齿
  • 、写入Shellcode到注册表上线
  • .“空心村”成因分析及解决对策122344
  • .NET 8 中引入新的 IHostedLifecycleService 接口 实现定时任务
  • .NET C# 使用 SetWindowsHookEx 监听鼠标或键盘消息以及此方法的坑
  • .net6Api后台+uniapp导出Excel
  • .NET企业级应用架构设计系列之技术选型
  • .net中应用SQL缓存(实例使用)
  • [2015][note]基于薄向列液晶层的可调谐THz fishnet超材料快速开关——
  • [3300万人的聊天室] 作为产品的上游公司该如何?
  • [Angular] 笔记 18:Angular Router
  • [BZOJ4010]菜肴制作
  • [Cocoa]iOS 开发者账户,联机调试,发布应用事宜
  • [CUDA手搓]从零开始用C++ CUDA搭建一个卷积神经网络(LeNet),了解神经网络各个层背后算法原理
  • [docker]docker网络-直接路由模式
  • [Docker]四.Docker部署nodejs项目,部署Mysql,部署Redis,部署Mongodb
  • [github配置] 远程访问仓库以及问题解决