热更新适配ibatis原理浅析

京东云开发者
• 阅读 88

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

在研发过程中,每个研发同学在联调、自测阶段中总会频繁的去执行编译、构建、打包的动作,遇到比较大的项目,执行一套流程下来,往往需要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的热加载。于是更新一个文件流程可以简化成如下流程:

热更新适配ibatis原理浅析

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

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

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

热更新适配ibatis原理浅析

三、ibatisPlugin 代码流程简介

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

热更新适配ibatis原理浅析

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的热更新场景,抛砖引玉,分享一些热更新的思路。整体开发过程中,还遇到了各种复杂的场景,以下是【藏经阁热更新插件】的整体结构图

热更新适配ibatis原理浅析

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

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

作者:京东零售 张骞

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

点赞
收藏
评论区
推荐文章
Karen110 Karen110
2年前
【前端自动化】如何使用Node.js实现热重载页面
前言前不久我结合browsersyncgulpgulpnodemon实现了一款生产环境热更新(我之前理解有点偏差,应该定义为热更新,不是热重载)的项目脚手架,那么,今天我们将使用Node.js实现一个热重载页面。那么,我今天就总结一下吧,以防止大家也跟我一样。热重载所谓热重载就是页面每次改动,不需要手动去刷新,可自动刷新。热更新浏览器的无刷新更新,允许在
Easter79 Easter79
2年前
springboot热部署实战
每次代码改动后都需要重新手动Run项目,心累,在网上找了下,发现SpringBoot提供了热部署的方案,改动代码后自动编译打包,现在将热部署的配置方法记下来:第一步:在pom.xml中添加依赖,导入springbootdevtools<dependency<groupIdorg.springframework
软件架构生态化-多角色交付的探索实践
作为一个技术架构师,不仅仅要紧跟行业技术趋势,还要结合研发团队现状及痛点,探索新的交付方案。在日常中,你是否遇到如下问题“业务需求排期长研发是瓶颈;非研发角色感受不到研发技改提效的变化;引入ISV团队又担心质量和安全,培训周期长“等等,基于此我们探索了一种新的技术体系及交付方案来解决如上问题。
Wesley13 Wesley13
2年前
unity热更(一)
Agenda•  什么是热更新•  为何要热更新•  如何在iOS 上对Unity 应用进行热更新•  支持UnityiOS 热更新的各种Lua 插件的对比什么是热更新• 广义定义• 无需关闭服务器,不停机状态下修复漏洞,更新资源等,重点是更新逻辑代码。• 狭义定义(iOS热更新)• 无需将代码重新打包提交至Ap
Stella981 Stella981
2年前
DevOps中的测试实践
万物皆可pipeline,流程自动化解放生产力。在DevOps的pipeline中,我们发现测试环节也需要一套流水线化的能力,来保证研发流程的大批pipeline稳定高品质交付。!(https://oscimg.oschina.net/oscnet/up4bbab1418ad0e9f554552e07d5d5ae0b508.png)下面介绍下De
Stella981 Stella981
2年前
SpringBoot依赖外置
背景近期有个SpringBoot的项目需要频繁更新,但是每次上传到服务器上几十MB,实在是花时间,所以打算优化打包方案,将第三方依赖外置流程首先使用SpringBoot打包插件将第三方排除,但是一些版本号同步更新的本地模块依赖需要放到一个jar中使用mavendependency插件将第三方依赖复制到构建目录中
Easter79 Easter79
2年前
SpringCloud(第 038 篇)idea环境热部署微服务开发
SpringCloud(第038篇)idea环境热部署微服务开发一、大致介绍1、我们在开发过程中,会经常需要启动、停止微服务,而且有时候会比较频繁,需要不停的操作启停动作;2、而我们本章节主要讲解下如何在开发环境中进行热部署,这样的话可以在一定程
京东云开发者 京东云开发者
11个月前
Flutter热更新技术探索 | 京东云技术团队
APP发布到市场后,难免会遇到严重的BUG阻碍用户使用,因此有在不发布新版本APP的情况下使用热更新技术立即修复BUG需求。原生APP(例如:Android&IOS)的热更新需求已经比较成熟,但Flutter技术栈目前还缺少类似的技术方案,因此Flutter研发团队,也需要类似的热更新技术。
京东云开发者 京东云开发者
10个月前
Spring Loaded代码热更新实践和原理分析 | 京东云技术团队
本文将深入探讨如何利用SpringLoaded热更新技术提高开发效率,减少编译和重启时间。分析SpringLoaded的热更新原理,以及实际应用过程中所需的操作和注意事项。
京东云开发者 京东云开发者
10个月前
APP流水线测试领域探索与最佳实践 | 京东物流技术团队
1背景APP端UI自动化因其特殊性(需连接测试机)一般都在本地执行,这种执行方式的局限性有以下弊端:1.时效性低:研发每次打包后都需要通知测试,测试再去打包平台取包,存在时间差1.研发自测或产品验收无法使用自动化脚本:研发自测及产品验收时如果想用自动化脚本