百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 软件资讯 > 正文

如何避免多个jar通过maven打包成jar,同名配置文件发生覆盖问题

ninehua 2024-12-13 15:33 32 浏览

前言

不知道大家在开发的过程中,有没有遇到这种场景,外部的项目想访问内部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

相关推荐

VMware ESXI系统镜像定制

为什么要定制ESXi镜像呢?原因很简单,那就是H3C比较老的服务器,比如我用的UISR390XG2服务器,是没有适配的ESXi部署镜像的。而我要部署的H3CloudOS添加节点时只能选择H3C...

最新保姆级、超详细介绍VMware的使用(一)软件的安装

一、VMware简介VMWare虚拟机软件是一个“虚拟PC”软件,它使你可以在一台机器上同时运行二个或更多Windows、DOS、LINUX系统。与“多启动”系统相比,VMware采用了完全不同的概...

微软提供免费Windows 11 虚拟机下载

据ZDNet11月23日报道,微软(Microsoft)提供了免费的Windows11企业版虚拟机以供下载。针对开发人员,微软表示,“通过使用带有最新版本的Windows、开发工具、sdk和准备好的...

VMware Workstation Pro 17.5安装包下载安装教程

软件简介VMwareWorkstationPro17.5是一款专业功能最强大的虚拟机软件,用户可以在虚拟机同时运行各种操作系统,进行开发、测试、演示和部署软件,虚拟机中复制服务器、台式机和平板环...

VMware vCenter Server 8.0U3c 发布下载,修复 U3b 更新停止响应的问题

VMwarevCenterServer8.0U3c发布下载,修复U3b更新停止响应的问题VMwarevCenterServer8.0U3c发布下载-集中式管理vSphere...

最新整套VMware Workstation 15 Pro 官方简体中文版 + 永久密钥

VMwareWorkstation是深受全球用户信赖并屡获殊荣的虚拟机软件。它可以在单台PC上运行多个、多平台、多层面的操作系统与应用程序。并且支持快照和克隆,支持物理机与虚拟机间复制、移动,交...

VMware16虚拟机安装教程

系统装机教程也告一段落,接下来秋水给大家讲讲虚拟机的安装,这里呢虚拟机选择VMware。一、安装教程1、在软件官网下载VMware安装包,或者在后台回复获取秋水下载好的安装包。2、双击软件进行安装,并...

VMware虚拟机12.1下载:修复Win10镜像识别错误等问题

IT之家讯12月9日消息,虚拟机软件VMwareWorkstation迎来12.1更新版本,本次更新为维护性更新,修复了之前版本中存在的一些问题,比如将Win10首个重大更新ISO镜像错误识别为W...

VMware vCenter Server 8.0U3b 发布下载,新增功能概览

VMwarevCenterServer8.0U3b发布下载,新增功能概览ServerManagementSoftware|vCenter请访问原文链接:https://sysin.or...

下载VMware虚拟机:打造全能多系统桌面,让IT技术探索触手可及!

VMware虚拟机打造全能多系统桌面,助力IT技术探索在当今科技飞速发展的时代,IT技术正以前所未有的速度渗透到生活和工作的方方面面。无论是智能硬件、移动应用还是云计算服务,都离不开IT技术的支撑。掌...

如何在vmware workstation player虚拟机上安装VMware Tools工具

版本:vmwareworkstation16player&ubuntu64位。首先我们使用vmwareworkstation16player启动ubuntu64位虚拟机,然后点击虚...

VMware与CentOS安装配置指南

以下是一份详细的VMware虚拟机安装、配置及CentOS系统安装配置的指南,适合新手逐步操作:一、VMware虚拟机安装与配置下载并安装VMware下载地址:访问VMware官网,选...

VMware虚拟机与物理机文件交互,这8种方法送给你

上一期我们讲解过用VMWare虚拟机打造一个金刚不坏之身的操作系统,小伙伴们反应说方法不错,只是虚拟机与物理机文件交互方式不好操作,这期应小伙伴们的要求,给大家讲解下虚拟机与物理机文件交互的8种方式,...

VMware 17.0 Pro 版本正式发布,还有适配MacOS 的 Fusion 13 Pro下载

VMware17.0Pro官方下载地址:【点击获取】私聊VMware17.0Pro的新功能特性容器和Kubernetes支持使用vctlCLI构建/运行/拉/推容器映像。支持在Works...

VMware Tools安装失败?手把手教你本地安装

VMwareTools安装失败?作为虚拟机与物理机之间的"桥梁",VMwareTools能实现文件拖拽、剪贴板共享、分辨率自适应等关键功能。没有它,VMware虚拟机就变得非常不好...