编译期动态替换三方包中的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打成jar后无法读取根路径和文件的解决

    springboot打成jar后无法读取根路径和文件的解决

    这篇文章主要介绍了springboot打成jar后无法读取根路径和文件的解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • SpringBoot自动重启的两种方法

    SpringBoot自动重启的两种方法

    我们在项目开发阶段,可能经常会修改代码,修改完后就要重启Spring Boot,本文主要介绍了SpringBoot自动重启的两种方法,具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12
  • java线程池使用后到底要关闭吗

    java线程池使用后到底要关闭吗

    这篇文章主要给大家介绍了关于java线程池使用后到底要不要关闭的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-01-01
  • 使用json字符串插入节点或者覆盖节点

    使用json字符串插入节点或者覆盖节点

    这篇文章主要介绍了使用json字符串插入节点或者覆盖节点的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • 微信支付java版本之获取Access_token

    微信支付java版本之获取Access_token

    这篇文章主要介绍了微信支付java版本之获取Access_token,java如何获取Access_token,感兴趣的小伙伴们可以参考一下
    2016-08-08
  • Springboot @Import 详解

    Springboot @Import 详解

    这篇文章主要介绍了Springboot @Import 详解,仔细看了下Springboot关于@Import的处理过程,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-11-11
  • Java阻塞队列四组API介绍(小结)

    Java阻塞队列四组API介绍(小结)

    这篇文章主要介绍了Java阻塞队列四组API介绍,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • java构造http请求的几种方式(附源码)

    java构造http请求的几种方式(附源码)

    本文主要介绍了java构造http请求的几种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • Java实现数据连接池Druid举例

    Java实现数据连接池Druid举例

    本文主要介绍了Java实现数据连接池Druid举例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • Java DOM4J方式生成XML的方法

    Java DOM4J方式生成XML的方法

    今天小编就为大家分享一篇Java DOM4J方式生成XML的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-07-07

最新评论