如何避免多个jar通过maven打包成jar,同名配置文件发生覆盖问题
ninehua 2024-12-13 15:33 4 浏览
前言
不知道大家在开发的过程中,有没有遇到这种场景,外部的项目想访问内部nexus私仓的jar,因为私仓不对外开放,导致外部的项目没法下载到私仓的jar,导致项目因缺少jar而无法运行。
通常遇到这种场景,常用的解法有,外部项目跟内部nexus的网络打通,比如通过VPN。或者将私仓的jar直接下载下来给到外部项目。对于第二种方案有时候因为私仓的jar里面有依赖其他的内部jar,导致要下载多个jar的情况。这时候为了方便,我们可能会将这些jar合并成一个大jar,再给出去。而目前有些jar都是一些starter,会有一些同名的配置文件,比如spring.factories。如果不进行处理,直接打包,就会出现同名配置文件覆盖的情况
本文就是要来聊聊当多个jar合并成一个jar,如何解决多个同名配置文件覆盖的情况
解决思路
通过maven-shade-plugin这个插件,利用插件的org.apache.maven.plugins.shade.resource.AppendingTransformer来处理处理多个jar包中存在重名的配置文件的合并。他的核心是在于合并多个同名配置文件内容,而非覆盖
示例配置如下
<build>
<plugins>
<!-- 防止同名配置文件,在打包时被覆盖,用来处理多个jar包中存在重名的配置文件的合并
参考dubbo:https://github.com/apache/dubbo/blob/master/dubbo-all/pom.xml-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.factories</resource>
</transformer>
<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>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.tooling</resource>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
打包后的配置文件的效果如下图
眼尖的朋友应该发现了,同名的配置内容是通过追加的方式,但仅仅追加,其实有时候还满足不了要求,比如spring.factories文件,他需要达到的效果应该是如下图
后面我通过maven-shade-plugin的官方示例(https://maven.apache.org/plugins/maven-shade-plugin/examples/resource-transformers.html)试图想找到解决方案,但是有点遗憾,没找到。于是在我面前就有两条路,一条是放弃maven-shade-plugin插件,比如选择其他类似的插件,比如maven-assembly-plugin,这种方案我试过,发现maven-assembly-plugin这个插件的扩展配置,比maven-shade-plugin复杂一些,于是放弃。最后选择了在maven-shade-plugin基础再扩展一下。
扩展的思路
我并没采用直接修改maven-shade-plugin插件的方式,而是在maven-shade-plugin打包后的基础上,再进行插件定制。实现的思路也不难,就是修改maven-shade-plugin打成jar后的spring.factories文件内容,将
调整成形如下即可
自定义maven插件spring-factories-merge-plugin
核心思路
1、如何读取配置文件spring.factories中key重复的内容,而不被覆盖
如果是直接使java.util.properties的读取,当配置文件中有key重复时,比如有多个org.springframework.boot.autoconfigure.EnableAutoConfiguration时,最后会出现value值被覆盖的情况。
解决方案,我们可以利用org.apacche.commons.configuration.PropertiesConfiguration来进行处理
在项目的pom引入GAV
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-configuration2</artifactId>
<version>${commons-configuration2}</version>
</dependency>
读取配置示例代码
@SneakyThrows
public static Map<String, Set<String>> readFactoriesFile(InputStream input) {
// 读取 spring.factories 内容
//利用PropertiesConfiguration取配置文件中key重复的内容,而不被覆盖
PropertiesConfiguration properties = new PropertiesConfiguration();
properties.read(new InputStreamReader(input));
Map<String, Set<String>> multiSetMap = new LinkedHashMap<>();
Iterator<String> keys = properties.getKeys();
while(keys.hasNext()) {
String key = keys.next();
String[] values = properties.getStringArray(key);
Set<String> collectSet = new LinkedHashSet<>();
buildKeyValues(values, collectSet);
multiSetMap.put(key,collectSet);
}
return multiSetMap;
}
2、如何将修改后的配置文件,重新写入jar
我这边的思路就是直接利用IO进行操作了
示例如下
public static void writeFactoriesFile(String factoriesBaseClassPathDir,String finalJarName) throws IOException {
String jarFilePath = String.format(factoriesBaseClassPathDir + "/target/" + finalJarName).replace("\\", "/").replaceAll("//+", "/");
if(!jarFilePath.endsWith(".jar")){
jarFilePath = jarFilePath + ".jar";
}
JarFile jarFile = new JarFile(jarFilePath);
if(jarFile != null){
List<JarEntry> jarFiles = jarFile.stream().collect(Collectors.toList());
@ Cleanup FileOutputStream fos = new FileOutputStream(jarFile.getName(), true);
@ Cleanup JarOutputStream jos = new JarOutputStream(fos);
for (JarEntry jarEntry : jarFiles) {
if(jarEntry.getName().startsWith(SpringFactoriesLoader.FACTORIES_RESOURCE_LOCATION)){
try {
@ Cleanup InputStream input = jarFile.getInputStream(jarEntry);
Map<String, Set<String>> factoriesMap = readFactoriesFile(input);
jos.putNextEntry(new JarEntry(jarEntry.getName()));
generateFactoriesContent(factoriesMap,jos);
} catch (IOException e) {
e.printStackTrace();
}
}else{
//表示将该JarEntry写入jar文件中 也就是创建该文件夹和文件
jos.putNextEntry(new JarEntry(jarEntry));
jos.write(streamToByte(jarFile.getInputStream(jarEntry)));
}
}
}
}
项目中如何配置插件
<build>
<plugins>
<!-- 防止同名配置文件,在打包时被覆盖,用来处理多个jar包中存在重名的配置文件的合并
参考dubbo:https://github.com/apache/dubbo/blob/master/dubbo-all/pom.xml-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.factories</resource>
</transformer>
<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>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.tooling</resource>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.github.lybgeek.jar</groupId>
<artifactId>spring-factories-merge-plugin</artifactId>
<version>0.0.1-SNAPSHOT</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>springFactoriesMerge</goal>
</goals>
</execution>
</executions>
<configuration>
<factoriesBaseClassPathDir>${basedir}</factoriesBaseClassPathDir>
<finalJarName>${project.artifactId}-${project.version}</finalJarName>
</configuration>
</plugin>
</plugins>
</build>
这边有个小细节是当maven-shade-plugin和spring-factories-merge-plugin的执行生命周期都是相同阶段,比如都是在package时,则maven-shade-plugin放置顺序得在spring-factories-merge-plugin之前,因为spring-factories-merge-plugin是对maven-shade-plugin打包后的结果进行二次加工。如果maven-shade-plugin不放置顺序得在spring-factories-merge-plugin之前,则spring-factories-merge-plugin的执行阶段就要比maven-shade-plugin靠后,比如maven-shade-plugin在package阶段执行,则spring-factories-merge-plugin就得在install或者deploy阶段执行
打包后的效果图如下
总结
之前在看开源框架的时候,很经常都是聚焦在源码上,而不会去注意一些maven插件,这次因为有这打jar的需求。我发现不管是springboot还是dubbo本身就集成一些宝藏插件,比如这个maven-shade-plugin插件,我就是dubbo那边找到的,地址在
https://github.com/apache/dubbo/blob/master/dubbo-all/pom.xml
。比如版本占位符插件flatten-maven-plugin在dubbo和springboot都有看到使用。如果后面有对maven插件由需求,推荐可以从springboot或者dubbo那边去搜,估计会有意想不到的收获
demo链接
https://github.com/lyb-geek/springboot-learning/tree/master/springboot-jar-merge
- 上一篇:JDK1.8下载、安装、配置
- 下一篇:如何使用Axure制作交互文档?
相关推荐
- PS 2019软件分享 (免费分享) ps软件2019官方版网盘
-
小小愿景...
- ps基础操作调整图像大小 #平面设计
-
大家好,从今天开始我将制作PS系列课程,从入门到精通。这边我用到的PS软件是PSCC2019版本。·首先打开PS软件,然后做一个基础的设置。在菜单栏中找到编辑菜单,找到首选项,然后点击常规。在跳出对...
- 这才是真正王者PS,修图美得吓人!送你UltimateRetouch汉化插件
-
Photoshop能做什么?PS使用领域多到无法想象,只要从事图形相关工作,就需要它。UltimateRetouchV3.7.55汉化版是一款非常强大的PS人像精修磨皮调色扩展面板(win/mac...
- VAIO FH14笔记本评测:1.4Kg的高性能移动生产力 | 钛极客
-
VAIOFH14对于现代人来说,移动办公已经成为了主要工作模式。无论是公司还是家庭,一款轻薄且高性能的笔记本电脑,都成为了必须品。不知道大家对于轻薄工作本是什么印象,很多音视频内容创作者都认为它是一...
- 不吹不黑,PS最强样机插件Paper Panel,各种效果一键生成
-
俗话说得好工欲善其事,必先利其器想要成为一个优秀的设计...
- Mac软件 PS CC2019软件安装教程 mac版photoshop2021安装解决教程
-
编辑搜图请点击输入图片描述1、软件更新介绍AdobePhotoshop,简称“PS”,是一款图像处理软件。PS主要处理以像素所构成的数字图像,使用其众多的编修与绘图工具,可以有效地进行图片编辑工作。...
- 觉得PS太难学?其实超简单!PS系列教程之历史记录画笔工具的介绍
-
PS入门免费公开课第十一节PhotoshopCC2019历史记录画笔工具的介绍与运用课程介绍:本课程是一个免费的PS入门公开课,适合设计爱好者、初学者学习;Photoshop广泛运用于广告设计、网页设...
- Photoshop 2019 for Mac & Windows 永久版,不用激活?白嫖?
-
最近Adobe家的PS又更新了,头条老是有各种推送,尝试了几个发现都是骗人的。什么“点赞、转发、评论,然后私信就送”,后来都不了了之骗关注。在我尝试了度娘得到的N个网站之后,终于遇到了今天要分享的...
- 超实用PS教程!(零基础入门) ps基础教程新手入教程视频
-
应用领域:摄影后期;海报设计;文字设计;移动界面;淘宝美工;网页设计;LOGO...
- PS2018官方原版 v19.0 电脑版 ps2018版本怎么样
-
PS2018是一款图像处理软件,软件的界面也是十分的简洁又美观,其中操作使用也非常方便,是广大设计师、摄影师以及艺术家们必备的修图、P图神器的哦。同时软件现在可以让用户们使用便利的搜寻面板,在应用程序...
- Ps、Ai、Ae 全部换新标!考验辨别能力的时候到了
-
上月底,Adobe更新了品牌形象系统,最大的变化莫过于标志性红色的更鲜艳明亮。从多色到单一颜色的转变,可以确保其在所有尺寸和所有环境中都能有良好的适应性。具体可详细阅读这篇文章:Adobe更新LO...
- iPad版Photoshop CC应用开始接受公测申请
-
本周一,Adobe宣布适用于iPad的PhotoshopCC应用开始接受公测申请,这款备受期待的热门摄影/图片编辑工具将于今年晚些时候正式发布。目前Adobe已经向CreativeCloud订阅...
- Photoshop CC 2019从入门到精通视频教程(含素材)
-
适用对象:PhotoshopCC2019...
- PHOTOSHOP历年版本启动画面大全 ps历届版本
-
PS2.5PS3.0PS4.0PS5.0PS6.0PS7.0PSCSPSCS2PSCS3PSCS4PSCS5PSCS6...
- 完全免费Adobe Photoshop CC 2018图文安装步骤教程附Ps2018安装包
-
软件介绍软件名称:AdobePhotoshopCC2018...