编译期动态替换三方包中的Class文件过程详解

 更新时间:2023年03月27日 16:19:44   作者:红兔哥  
这篇文章主要为大家介绍了编译期动态替换三方包中的Class文件过程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

背景

最近做业务时遇到一个问题,客户想在底层数据添加一个字段,只能乖乖的添加表字段、实体添加对应属性,一切都在预期中进行这,但是这个工程是经过二开的,展示层实体没法直接添加,于是想当然继承实体扩展字段,没想到顶层一堆Request、Response,如果一个一个进行扩展马也得累死,于是就思考有没有简便的方法仅对目标实体进行操作来完成字段添加的方法。

思考过程

在Java中要在类中添加字段属性,除了显示编码外,还有一种技术就是编译期间动态修改,比如Lombok、Mapstruct等都是在编译期动态生成代码,提高编码效率,所以我也考虑通过这种方式编译期添加目标字段属性,百度了一通没有合适的方式动态添加,但是手写通过字节码注入一定是可以实现的,想想成本还是有点高,赶紧转换思路,既然不能动态插入字段,那能不能直接替换目标类呢?一想到这就有戏,在Java中加载类是通过类加载器进行加载的,有了依据后赶紧接着百度,果不然让我发现一种方式,通过maven插件的方式实现,客官接着往下看。

一般情况下不建议用这么hack的方式哈,尽量保持三方包的新鲜度,避免未来升级导致的兼容性问题。

主角出场

主角:maven-dependency-plugin

这仅仅是处理的一种方式,大家如果有更好的处理方式,可以放到评论区,我们一起讨论,互相学习进步。

实现原理

通过配置maven-dependency-plugin, 可以将我们指定的dependency解压到项目的class目录中,设置不覆盖本地项目相同class文件(类的全限定名相同),就实现了本地文件替换三方jar中类文件的目的了。

在Java应用中,如果存在多个同名类,最终只会加载一个目标类,到底会加载哪个同名类是又类加载器的双亲委派机制决定的,先请求父类加载器加载,父类无法加载回到应用程序加载器,应用程序无法加载就会到类路径下即class目录中加载,如果仍然不存在会到依赖中进行加载。

基于以上原理,实现类文件覆盖就有了依据,那么接下来具体实践演示下。

使用

这里我使用commons-lang3举例。

第一步:配置Maven插件

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>3.1.2</version>
    <executions>
        <execution>
            <!-- unpack任务标识符,unpack是将依赖从仓库中解压到指定目录 -->
            <id>unpack</id>
            <!-- unpack任务默认执行阶段 -->
            <phase>generate-sources</phase>
            <goals>
                <!-- 目标功能:unpack -->
                <goal>unpack</goal>
            </goals>
            <configuration>
                <artifactItems>
                    <artifactItem>
                        <groupId>org.apache.commons</groupId>
                        <artifactId>commons-lang3</artifactId>
                        <!-- 设置为false,依赖解压到目录时不会进行覆盖,设置为true则会覆盖 -->
                        <overWrite>false</overWrite>
                        <!-- 目标class文件输出目录 -->
                        <outputDirectory>${project.build.directory}/classes</outputDirectory>
                    </artifactItem>
                </artifactItems>
            </configuration>
        </execution>
    </executions>
</plugin>

第二步:编译工程

这一步还没有定义目标类,暂时仅是将目标三方包的类放到了class目录下,标红的位置是即将要进行修改的位置。

第三步:添加目标类

  • 包名和目标类所在包名完全一致;
  • 类名保持一致;

第四步:重新编译工程

至此已经能够看到效果了,整个方式过程也比较简单,去掉中间的编译过程,总共两步。

总结

这种Hack的方式在业务编码中建议少用,通过上边的方式虽然能解决问题,但同时也引入了一些副作用,一方面相当于依赖包引入两份,另一方面当依赖包升级时可能存在疏漏。看看学习学习,多一种解决方式多一条路,希望大家每天编码顺顺利,我就先溜了!

以上就是编译期动态替换三方包中的Class文件过程详解的详细内容,更多关于编译期动态替换Class文件的资料请关注脚本之家其它相关文章!

相关文章

  • springboot整合阿里云oss上传的方法示例

    springboot整合阿里云oss上传的方法示例

    这篇文章主要介绍了springboot整合阿里云oss上传的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • hibernate批量操作实例详解

    hibernate批量操作实例详解

    这篇文章主要介绍了hibernate批量操作,结合实例形式分析了Hibernate实现批量插入,更新及删除等操作的具体实现技巧,需要的朋友可以参考下
    2016-03-03
  • 浅析java贪心算法

    浅析java贪心算法

    这篇文章简单主要介绍了java贪心算法,包含贪心算法的基本思路,性质,以及实现示例,有需要的小伙伴参考下
    2015-02-02
  • 浅谈基于SpringBoot实现一个简单的权限控制注解

    浅谈基于SpringBoot实现一个简单的权限控制注解

    这篇文章主要介绍了基于SpringBoot实现一个简单的权限控制注解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • Java NIO.2 使用Path接口来监听文件、文件夹变化

    Java NIO.2 使用Path接口来监听文件、文件夹变化

    Java7对NIO进行了大的改进,新增了许多功能,接下来通过本文给大家介绍Java NIO.2 使用Path接口来监听文件、文件夹变化 ,需要的朋友可以参考下
    2019-05-05
  • Java通过Fork/Join优化并行计算

    Java通过Fork/Join优化并行计算

    这篇文章主要为大家详细介绍了Java通过Fork、Join来优化并行计算,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • Java中的Apache Commons Math使用详解

    Java中的Apache Commons Math使用详解

    Java中的Apache Commons Math是一个开源的数学库,它提供了许多常用的数学函数和算法,这个库对于需要处理大量数据的开发者来说非常有用,因为它可以大大简化代码并提高效率,本文给大家详解讲解Java中的Apache Commons Math知识,感兴趣的朋友跟随小编一起看看吧
    2023-08-08
  • java背包问题动态规划算法分析

    java背包问题动态规划算法分析

    这篇文章主要介绍了java背包问题动态规划算法分析,想了解算法的同学一定要看一下
    2021-04-04
  • java 线程方法join简单用法实例总结

    java 线程方法join简单用法实例总结

    这篇文章主要介绍了java 线程方法join简单用法,结合实例形式总结分析了Java线程join方法的功能、原理及使用技巧,需要的朋友可以参考下
    2019-11-11
  • Java8新特性之接口中的默认方法和静态方法

    Java8新特性之接口中的默认方法和静态方法

    这篇文章主要介绍了Java8新特性之接口中的默认方法和静态方法的相关资料,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07

最新评论