热更新适配ibatis原理浅析
一、热更新解决了什么问题?
在研发过程中,每个研发同学在联调、自测阶段中总会频繁的去执行编译、构建、打包的动作,遇到比较大的项目,执行一套流程下来,往往需要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原理浅析的更多相关文章
- 手把手教你实现热更新功能,带你了解 Arthas 热更新背后的原理
文章来源:https://studyidea.cn/java-hotswap 一.前言 一天下午正在摸鱼的时候,测试小姐姐走了过来求助,说是需要改动测试环境 mock 应用.但是这个应用一时半会又找不 ...
- SpringBoot魔法堂:应用热部署实践与原理浅析
前言 后端开发的同学想必每天都在重复经历着修改代码.执行代码编译,等待--重启Tomcat服务,等待--最后测试发现还是有bug,然后上述流程再来一遍(我听不见)
- APP热更新方案
为什么要做热更新 当一个App发布之后,突然发现了一个严重bug需要进行紧急修复,这时候公司各方就会忙得焦头烂额:重新打包App.测试.向各个应用市场和渠道换包.提示用户升级.用户下载.覆盖安装. 重 ...
- 【笔记】Nginx热更新相关知识
(以下学习笔记内容均摘自参考链接,仅供个人查阅) 1.inotify文件系统监控特性 Inotify 是一个 Linux 内核特性,它监控文件系统,并且及时向专门的应用程序发出相关的事件警告,比如 ...
- RN热更新
说白了集成RN业务,就是集成RN离线包,解析并渲染.所以,RN热更新的根本原理就是更换js bundle文件和资源文件,并重新加载,新的内容就完美的展示出来了. 目前市场上出现的3种热更新模式如下:仅 ...
- Android 热更新是如何实现的?
Android开发中,我们常常遇到热更新这个概念,而这个热更新具体是怎么实现的呢?今天在网上看到一个大神分享的热更新相关实现原理和实现代码,感觉灰常不错,分享给广大码农盆友look look . Cl ...
- APP热更新方案(转)
本文转载自[http://creator.cnblogs.com/] 博客地址:Zealot Yin 为什么要做热更新 当一个App发布之后,突然发现了一个严重bug需要进行紧急修复,这时候公司各方就 ...
- 移动端APP热更新方案(iOS+Android)
出自:http://www.cnblogs.com/Creator/p/7007694.html 为什么要做热更新 当一个App发布之后,突然发现了一个严重bug需要进行紧急修复,这时候公司各方就会忙 ...
- 深入理解xLua热更新原理
热更新简介 热更新是指在不需要重新编译打包游戏的情况下,在线更新游戏中的一些非核心代码和资源,比如活动运营和打补丁.热更新分为资源热更新和代码热更新两种,代码热更新实际上也是把代码当成资源的一种热更新 ...
- 深入理解xLua基于IL代码注入的热更新原理
目前大部分手游都会采用热更新来解决应用商店审核周期长,无法满足快节奏迭代的问题.另外热更新能够有效降低版本升级所需的资源大小,节省玩家的时间和流量,这也使其成为移动游戏的主流更新方式之一. 热更新可以 ...
随机推荐
- Karmada v1.2发布:开启全文本搜索新纪元
摘要:Karmada v1.2 版本对调度器能力做了较大增强,初步提供了分布式搜索引擎支持,此外还借助聚合API提供了诸如 logs, watch等实用的命令行工具,资源解释器(Resource In ...
- SpringBoot Scheduled 常见用法
外部统一管理可用 xxl-job ,将各定时任务集中管理,灵活改变执行频率,支持某一个定时器集群处理,避免多服务启动时,每个服务都执行(重复执行) 比如我的API服务里有一个定时任务,将API做成集群 ...
- selenium-web自动化(po模型)
什么是po模型呢?简单理解就是:把每个页面当成一个对象,给这些页面当成一个类,主要就是完成元素定位和业务操作:把它和测试脚本区分开来,需要什么取这些页面类去调用即可.这样的好处在于页面元素发生变化时, ...
- 鸿蒙HarmonyOS实战-工具安装和Helloworld案例
前言 HarmonyOS是华为自主开发的操作系统,它在2020年9月正式发布.它最初被称为鸿蒙OS,后来更名为HarmonyOS.HarmonyOS旨在提供一种可在各种设备上无缝运行的统一操作系统,包 ...
- 记一次 .NET某MES自动化桌面程序 卡死分析
一:背景 1. 讲故事 前些天有位朋友在微信上找到我,说他们的客户端程序卡死了,让我帮忙看下是什么原因导致的?dump也拿到了手,既然有了dump就开始正式分析吧. 二:WinDbg 分析 1. 什么 ...
- leaflet 绘制 带箭头的线
箭头不是画的线段,是贴的图标,再按方向旋转一下. 代码: //添加箭头线 function addLineDirection(polylinePointArr, source, target) { v ...
- 《对线面试官》| 高频 Python 面试题 pt.1
1.聊聊 python 中的值传递和引用传递吧 值传递: 值传递意味着在函数调用时,将实际参数的值复制一份传递给函数的形式参数 在函数内部,形式参数将作为局部变量使用,对形式参数的修改不会影响原始变量 ...
- 汇编 | 数据段寄存器DS和[address]
Description CPU要读写一个内存单元的时候,必须先给出这个内存单元的地址,在8086PC中,内存地址由段地址和偏移地址组成.8086CPU中有一个DS寄存器,通常用来存放要访问 数据的段地 ...
- Codeforces 189 A. Cut Ribbon(DP 恰装满的完全背包问题)
题目链接 Polycarpus has a ribbon, its length is n. He wants to cut the ribbon in a way that fulfils the ...
- 如何用 Serverless 一键部署 Stable Diffusion?
思路 其实很简单, 我们只需要将镜像里面的动态路径映射到 NAS文件存储里面即可,利用 NAS 独立存储文件模型,扩展,语言包等,并且我们可以为管理 NAS 单独配置一个可视化的后台,用简单的文件上传 ...