一、热更新解决了什么问题?

在研发过程中,每个研发同学在联调、自测阶段中总会频繁的去执行编译、构建、打包的动作,遇到比较大的项目,执行一套流程下来,往往需要3-10分钟左右,极大的降低了研发的速度,基于以上痛点,我们基于JAVA Agent技术开发出一套插件【藏经阁热更新插件】,通过热更新方式,实现了修改代码即时生效,极大的降低研发的打包、发布时间,提升研发效率。目前这套插件已经兼容多个场景。

二、ibatis如何进行热更新的?

热更新是什么?就是在目标JVM不停服的情况下,动态的更新一个class文件、xml文件,使程序的运行逻辑随之改变。比如加一行日志,执行热更新后就可以查看日志,修改sql语句就可以直接获取对应结果。

如果要实现修改ibatis框架中的配置文件怎么实现呢?

ibatis配置文件包含两个,一个是SqlMapConfig.xml,这个配置文件为我们提供了持久化所需的数据源配置,一个是sqlMapper.xml,这个配置文件定义了iBATIS- SQL映射语句,我们的目的是修改sqlMapper.xml中的sql语句,可以即时生效。在spring中,spring为我们提供了一个iBatis的工厂类,SqlMapClientFactoryBean,

<bean id="sqlMapClientFactoryBean" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="dataSource" ref="masterDataSourcePool"/>
<property name="configLocation" value="classpath:sqlConfig.xml"/>
<property name="mappingLocations" value="classpath:sqlMapper.xml"/>
</bean>

一个jdos应用,一般是通过这个工厂类将ibatis与spring整合起来,所以在修改sqlMapper.xml文件后,同时需要重新加载这个bean。 热更新我们是通过dcevm来实现。dcevm可以热更新类,但也有一定的局限性,其中面临的一个问题是,被spring管理的bean和以及配置文件在初始化时候就被缓存好了,单纯的修改配置文件无法触发重新扫描。

所以我们需要在相关bean重新加载后清空springmvc缓存,重新触发扫描接口方法,进而实现相关bean的热加载。于是更新一个文件流程可以简化成如下流程:

在这个流程中,我们根据不同的场景去选择不同的插件plugin,通过plugin实现不同的监听方法。那么在具体的实现过程中,如果服务端收到很多变更配置文件,又如何来判断变更的文件哪些是ibatis配置信息呢?

通过了解ibatis的原理,结合agent的插桩技术,我们可以在JDos应用启动过程中,监听这个类(SqlMapClientFactoryBean)的加载事件,在这个类被加载的时候,写入一些处理方法,把ibatis的配置文件信息先保存一份,这样在更新的时候,我们可以通过缓存的路径来判断,是否是同一类型的配置。

我们发现SqlMapClient 接口主要定义了客户端的操作行为包括 select、insert、update、delete,“SqlMapExecutorDelegate” 这个类是执行代理类。这个类他耦合了用户端的执行操作行为和执行的环境,他持有执行操作的所需要的数据,同时提供着执行操作依赖的环境。其中有个状态mappedStatements,如果在每次更新文件后,不对他进行清空操作,修改的sql是不会生效的。而这个清空缓存方法,需要我们自己实现。这样在jdos应用启动的时候,我们可以增加如下流程:

三、ibatisPlugin 代码流程简介

接下来从代码视角,简单阐述整体流程

2.1 应用启动后,加载agent的jar包,首先会初始化插件pluginManager.getInstance().init(),扫描这个包路径

 com.jd.plus.hot.deploy.core.plugin

下面的@Plugin注解信息,然后注册插件信息,其中就包含springPlugin、ibatisPlugin等插件,插件的方法上会通过@OnResourceFileEvent注解方式,在资源变更后反射调用该方法。进而更新不同的文件信息缓存,同时会根据不同的类触发事件,写入不同的缓存信息,根据事件@OnClassLoadEvent(classNameRegexp = "com.ibatis.sqlmap.engine.builder.xml.SqlMapConfigParser") 写入sqlMapConfig配置信息,根据事件SqlMapClientFactoryBean注册配置文件内容,根据事件“SqlMapExecutorDelegate”添加清空缓存方法clearMapperState

这里需要着重说一下@plugin插件。不同的框架去实现热加载,主要是通过插件体系实现。@plugin是用来声明插件的,一个插件具体包含如下几个部分


@Init用来注解字段,类似Spring里的@Autowired,目前支持初始化的参数有:
1.PluginManager: 插件全局的相关配置在这个里面
2.Watcher: 监听器,可以通过监听器监听别的目录
3.ExecuteScheduler: 调度器,用来调度任务
4.HotswapTransformer: 用来转换类
5.PluginConfiguration:插件配置相关的逻辑在这个类里 @OnClassLoadEvent、@OnResourceLoadEvent用来注解方法,用来插桩,init方法获取配置文件,获取完成后,通过WatcherUtils.registerExtraClassPathListener来监听log4j配置文件的变动。配置文件变动后,再调用reload方法热加载。

2.2 agent监听文件,agent启动初始化一个监听器,使用的是NIO的fileSystems.getDefault().newWatchService 监听所有的文件资源,watcher启动一个线程,循环的从系统事件取出WatchEvent,放到dispatcher的队列中。

2.3 dispatcher 从队列中取出event,通过callListener通知监听者

2.4 IBatisPlugin.class中的监听方法,获取到 filter = ".*.xml" 的请求,通过路径比对,确定是否属于Ibatis的相关配置。

2.5 调用方法clearMapperState清空注册的文件缓存信息,重新写入新的变更文件。

2.6 通过XmlBeanRefreshCommand命令重新加载xml中的bean,刷新缓存,reloadBeanFromxml,完成热加载

四、相关技术

JAVA-Agent:简单来说,是就是通过Instrumentation API与虚拟机交互,在启动时配置相关的参数(-javaagent),其premain方法会在程序main方法执行之前被调用,此时大部分Java类都没有被加载,可以对类加载埋点(addTransformer)。同时实现 监听到类的变动-->然后调用Instrumentation#redefineClasses去重新加载代码

五、总结

本文主要是通过适配ibatis的热更新场景,抛砖引玉,分享一些热更新的思路。整体开发过程中,还遇到了各种复杂的场景,以下是【藏经阁热更新插件】的整体结构图

还没有使用插件的小伙伴,欢迎大家积极使用,并在评论区发表对插件的建议和想法。

技术达人们,还对哪些插件的原理更感兴趣呢?欢迎在评论区留言,我们将根据大家的反馈,积极推出更多的分享。

作者:京东零售 张骞

来源:京东云开发者社区 转载请注明来源

热更新适配ibatis原理浅析的更多相关文章

  1. 手把手教你实现热更新功能,带你了解 Arthas 热更新背后的原理

    文章来源:https://studyidea.cn/java-hotswap 一.前言 一天下午正在摸鱼的时候,测试小姐姐走了过来求助,说是需要改动测试环境 mock 应用.但是这个应用一时半会又找不 ...

  2. SpringBoot魔法堂:应用热部署实践与原理浅析

    前言 后端开发的同学想必每天都在重复经历着修改代码.执行代码编译,等待--重启Tomcat服务,等待--最后测试发现还是有bug,然后上述流程再来一遍(我听不见)

  3. APP热更新方案

    为什么要做热更新 当一个App发布之后,突然发现了一个严重bug需要进行紧急修复,这时候公司各方就会忙得焦头烂额:重新打包App.测试.向各个应用市场和渠道换包.提示用户升级.用户下载.覆盖安装. 重 ...

  4. 【笔记】Nginx热更新相关知识

    (以下学习笔记内容均摘自参考链接,仅供个人查阅)   1.inotify文件系统监控特性 Inotify 是一个 Linux 内核特性,它监控文件系统,并且及时向专门的应用程序发出相关的事件警告,比如 ...

  5. RN热更新

    说白了集成RN业务,就是集成RN离线包,解析并渲染.所以,RN热更新的根本原理就是更换js bundle文件和资源文件,并重新加载,新的内容就完美的展示出来了. 目前市场上出现的3种热更新模式如下:仅 ...

  6. Android 热更新是如何实现的?

    Android开发中,我们常常遇到热更新这个概念,而这个热更新具体是怎么实现的呢?今天在网上看到一个大神分享的热更新相关实现原理和实现代码,感觉灰常不错,分享给广大码农盆友look look . Cl ...

  7. APP热更新方案(转)

    本文转载自[http://creator.cnblogs.com/] 博客地址:Zealot Yin 为什么要做热更新 当一个App发布之后,突然发现了一个严重bug需要进行紧急修复,这时候公司各方就 ...

  8. 移动端APP热更新方案(iOS+Android)

    出自:http://www.cnblogs.com/Creator/p/7007694.html 为什么要做热更新 当一个App发布之后,突然发现了一个严重bug需要进行紧急修复,这时候公司各方就会忙 ...

  9. 深入理解xLua热更新原理

    热更新简介 热更新是指在不需要重新编译打包游戏的情况下,在线更新游戏中的一些非核心代码和资源,比如活动运营和打补丁.热更新分为资源热更新和代码热更新两种,代码热更新实际上也是把代码当成资源的一种热更新 ...

  10. 深入理解xLua基于IL代码注入的热更新原理

    目前大部分手游都会采用热更新来解决应用商店审核周期长,无法满足快节奏迭代的问题.另外热更新能够有效降低版本升级所需的资源大小,节省玩家的时间和流量,这也使其成为移动游戏的主流更新方式之一. 热更新可以 ...

随机推荐

  1. 敏捷开发专家一席谈:云原生技术下的华为云DevOps实践之路

    摘要:听华为云DevCloud首席技术布道师徐毅讲述云原生下的DevOps实践. 本文分享自华为云社区<敏捷开发专家一席谈:云原生技术下的华为云DevOps实践之路>,作者:华为云社区精选 ...

  2. JerryScript:物联网开发者的得力工具

    摘要:本文档以Linux开发环境及realview-pbx-a9开发板为例,简单介绍LiteOS上jerryscript命令的使用. 本文分享自华为云社区<Jerryscript-让开发者事半功 ...

  3. 玩转Python:用Python处理文档,5个必备的库,特别实用,附代码

    在Python中,有几个流行的库用于处理文档,包括解析.生成和操作文档内容.以下是一些常用的库及其简介和简单的代码示例: PyPDF2 - 用于处理PDF文件. 简介:PyPDF2是一个纯Python ...

  4. 【每日一题】15.Xorto (前缀和枚举)

    补题链接:Here 题意:选取任意不重叠的两个区间,使异或结果为 \(0\) 样例:\(1,2,3,4,5,5\) 在样例中我们可以选取 \(1,2,3\) 和 \(5,5\) 就是满足题意 思路:相 ...

  5. 【每日一题】2.合并回文子串 (字符串处理 + 区间DP)

    题目链接:Here 遇到这种数据范围较小的计数问题应该优先考虑dp,本题就是如此. 那么应该怎么样考虑转移呢? 首先最后C中的那个价值最大的子串一定是由字符串A的一个区间和字符串B的一个区间合并得到的 ...

  6. 在wsl2 kali发行版中安装docker

    前言 因为不想开虚拟机,而又需要多个linux发行版来做测试,也不想使用docker-desktop来曲线救国,所以想直接安装个docker随时使用,这一路也是踩了不少坑.直接复制进终端进行安装 su ...

  7. 入门篇-其之十一-流程控制之break和continue关键字

    本文中使用到的工具是Intellij IDEA和JDK 8,需要安装两款工具的请查看这两篇教程:点我查看安装JDK8/11/17教程.点我查看安装Intellij IDEA教程. 一.循环的嵌套 和前 ...

  8. 【调试】kprobes(一)基本概念

    简介 开发人员在内核或者模块的调试过程中,往往会需要要知道其中的一些函数有无被调用.何时被调用.执行是否正确以及函数的入参和返回值是什么等等. 比较简单的做法是在内核代码对应的函数中添加日志打印信息, ...

  9. 关于el-upload上传图片的一些坑clearFiles()的使用

    https://blog.csdn.net/weixin_46421824/article/details/109195624?spm=1001.2101.3001.6661.1&utm_me ...

  10. POJ

    //poj 2080//题目大意:给定天数,从2000年1月1日经过这些天后的 年 月 日 及 星期几//代码参照大牛的写的,本人还是处于菜鸟阶段,思路很好#include<stdio.h> ...