前言

前天项目中使用了mybatis-plus,但是搭配Jrebel开发项目时,发现修改mapper的xml,或者mapper方法中的注解,Jrebel并没有能够reload mapper.于是就有了本篇文章

探索

为了解决这个问题,首先想到的是到mybatis-plus官网查看配置方法,官网中的文档热加载很清楚说明了

3.0.6版本上移除了该功能,不过最新快照版已加回来并打上废弃标识,3.1.0版本上已完全移除

按照官网配置

  1. @Bean
  2. @Profile("dev") //
  3. public MybatisMapperRefresh mybatisMapperRefresh (MybatisPlusProperties properties, SqlSessionFactory sessionFactory){
  4. return new MybatisMapperRefresh(properties.resolveMapperLocations(), sessionFactory, true);
  5. }

上述配置后重新运行项目,修改mapper,发现并没有生效,于是开始研究他的源码。
通过查看MybatisMapperRefresh源码发现他的实现方式:重建mapper来实现热加载的。

  1. XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(resource.getInputStream(),
  2. sqlSessionFactory.getConfiguration(),
  3. resource.toString(), sqlSessionFactory.getConfiguration().getSqlFragments());
  4. xmlMapperBuilder.parse();

最终定位到关键代码

  1. /**
  2. * MybatisPlus 加载 SQL 顺序:
  3. * <p>1、加载XML中的SQL</p>
  4. * <p>2、加载sqlProvider中的SQL</p>
  5. * <p>3、xmlSql 与 sqlProvider不能包含相同的SQL</p>
  6. * <p>调整后的SQL优先级:xmlSql > sqlProvider > curdSql</p>
  7. */
  8. @Override
  9. public void addMappedStatement(MappedStatement ms) {
  10. logger.debug("addMappedStatement: " + ms.getId());
  11. if (mappedStatements.containsKey(ms.getId())) {
  12. /*
  13. * 说明已加载了xml中的节点; 忽略mapper中的SqlProvider数据
  14. */
  15. logger.error("mapper[" + ms.getId() + "] is ignored, because it exists, maybe from xml file");
  16. return;
  17. }
  18. super.addMappedStatement(ms);
  19. }

注:Mybatisplus重写了mybatis的Configuration类(这也是Jrebel 无法热加载SQL maps)的原因之一

上面添加MappedStatementConfiguration时先判断了是否已经加载过,但是项目启动时,Configuration已加载了所有的MappedStatement,所以MybatisMapperRefresh 这个后台线程后面reload完全没有作用.

开搞

为了弄清楚JRebel是如何实现mybatis热加载。

我把jrebel的插件作为libary,添加到工程里.

利用IDEA 天然的反编译功能,顺利成章的看到了源码
下面是mybatis热加载插件的主入口

  1. public void preinit() {
  2. ClassLoader cl = MyBatisPlugin.class.getClassLoader();
  3. Integration integration = IntegrationFactory.getInstance();
  4. integration.addIntegrationProcessor(cl, "org.apache.ibatis.io.Resources", new ResourcesCBP());
  5. integration.addIntegrationProcessor(cl, new String[]{"org.apache.ibatis.builder.xml.XMLConfigBuilder", "pl.atena.ibatisbaf.core.config.ConfigBuilder"}, new XMLConfigBuilderCBP());
  6. integration.addIntegrationProcessor(cl, "org.apache.ibatis.session.defaults.DefaultSqlSessionFactory", new DefaultSqlSessionFactoryCBP());
  7. integration.addIntegrationProcessor(cl, "org.apache.ibatis.session.Configuration", new ConfigurationCBP());
  8. integration.addIntegrationProcessor(cl, "org.apache.ibatis.session.Configuration$StrictMap", new StrictMapCBP());
  9. integration.addIntegrationProcessor(cl, "org.apache.ibatis.binding.MapperRegistry", new MapperRegistryCBP());
  10. integration.addIntegrationProcessor(cl, "org.apache.ibatis.reflection.Reflector", new ReflectorCBP());
  11. integration.addIntegrationProcessor(cl, "org.apache.ibatis.reflection.DefaultReflectorFactory", new DefaultReflectorFactoryCBP());
  12. integration.addIntegrationProcessor(cl, "org.mybatis.spring.SqlSessionFactoryBean", new SqlSessionFactoryBeanCBP());
  13. integration.addIntegrationProcessor(cl, "org.apache.ibatis.builder.annotation.MapperAnnotationBuilder", new MapperAnnotationBuilderCBP());
  14. integration.addIntegrationProcessor(cl, "org.apache.ibatis.type.TypeAliasRegistry", new TypeAliasRegistryCBP());
  15. integration.addIntegrationProcessor(cl, "org.apache.ibatis.plugin.InterceptorChain", new InterceptorChainCBP());
  16. integration.addIntegrationProcessor(cl, "org.mybatis.spring.mapper.MapperFactoryBean", new MapperFactoryBeanCBP());
  17. integration.addIntegrationProcessor(cl, "org.mybatis.spring.annotation.MapperScannerRegistrar", new MapperScannerRegistrarCBP());
  18. integration.addIntegrationProcessor(cl, "org.apache.ibatis.binding.MapperProxy", new MapperProxyCBP());
  19. }

JRebel在应用启动时对mybatis的某些类做了Hook(利用Javaassit)

上述的类都是和Mapper相关的(Mapper文件解析,Mapper 注解解析…)

由于mybatis-plus重写了mybatis的一些核心类(而JRebel的插件对mybatis中的关键类做了HOOK),所以导致项目中整合mybatis-plus时,修改了mapper没有被热加载.

为了使mybatis-plus也能够热加载,我想到了hook Mybatis-plus中的关键类,于是阅读了mybatis-plus的源码,整理出如下mp重写的mybatis类。

  • MybatisConfiguration.java
  • MybatisMapperAnnotationBuilder.java
  • MybatisSqlSessionFactoryBean.java
  • MybatisMapperProxy.java

然后趁IDEA不注意的时候,去Jrebel的官网找到了开发自定义插件的文档Custom JRebel plugins.
最终写了这个插件。

PS:其中大部分的代码来自原插件反编译后代码,同时结合Mybatis-plus重写的源码,做了相应适配.

下面是插件源码地址:

jrebel-mybatisplus

下面是插件下载地址:

jr-mybatisplus.zip

如何使用请阅读README.md

使用

将下载好的插件jr-mybatisplus.zip解压并拷贝至任意目录, 比如: d:\jrebel\plugin\jr-mybatisplus.jar

打开你的IDE(Intellij IDEA or Eclipse),修改运行配置,增加VM参数:-Drebel.plugins=d:\jrebel\plugin\jr-mybatisplus.jar,然后以JRebel方式启动

检查插件是否生效:

修改你项目中的mapper xml 文件后,重新编译,如果重新请求接口,你应该会看到控制台输出 “Reloading SQL maps”

总结

    • 学习了javaassit的使用.

    • 阅读了mybatis && mybatis-plus 的源码,了解到mybatis的实现原理,以及mybatis-plus的相关原理.

    • 学习了JRebel的插件开发方式以及它的Hot Reloading原理.

文章来源:https://githuboy.online/2019/05/11/基于JRebel开发的MybatisPlus热加载插件/

基于JRebel开发的MybatisPlus热加载插件的更多相关文章

  1. idea开发maven项目热加载

    JavaWeb项目,尤其是一些大型项目,在开发过程中,启动项目耗费的时间就不短.大大的拖慢了开发速度!在这分享一种不需要插件就能实现热加载的方法! 默认已经创建好一个Maven项目 点击此按钮 点击 ...

  2. [Eclipse] - 集成Tomcat热加载插件

    使用Eclipse + Tomcat,要使用热加载,总是会重启tomcat webapp. 可以使用这个插件:jrebel 如果是Tomcat 7.0+版本,需要使用jrebel5.5.1+的版本,不 ...

  3. mybatis plus3.1.0 热加载mapper

    今天又开始写业务代码了,每次修改SQL都要重启服务,实在是浪费时间. 想起之前研究过的<mybatis plus3.1.0 热加载mapper>,一直没有成功,今天静下心来分析了问题,终于 ...

  4. java的热部署和热加载

    ps:热部署和热加载其实是两个类似但不同的概念,之前理解不深,so,这篇文章重构了下. 一.热部署与热加载 在应用运行的时升级软件,无需重新启动的方式有两种,热部署和热加载. 对于Java应用程序来说 ...

  5. SpringBoot在IntelliJ IDEA下for MAC 热加载

    说在前面 热加载:文件内容变更服务器自动运行最新代码.实则在IDEA环境进行热部署后,下述过程一气呵成. 1代码变更,文件自动保存(IDEA自动保存代码,用户无需使用COMMAND+SAVE快捷键): ...

  6. react热加载失败

    react热加载失败 原因:路径名字大小写错误, 不是全部加载失败,有的时候可以用,有的时候不可以 热加载插件:webpack-dev-server

  7. SpringBoot开发 - 什么是热部署和热加载?devtool的原理是什么?

    在SpringBoot开发调试中,如果我每行代码的修改都需要重启启动再调试,可能比较费时间:SpringBoot团队针对此问题提供了spring-boot-devtools(简称devtools)插件 ...

  8. 使用JRebel插件实现SpringBoot应用代码热加载

    前言 在实际的开发过程中,我们经常修改代码之后,手动的重启项目,查看修改效果.那么有没有一种方式能够快速的.自动的帮我们将修改代码自动更新,避免手动重启,从而提高开发效率呢?是有的,在我之前的文章里面 ...

  9. 最简破解-java代码热加载热部署IDEA插件JRebel

    如果经济实力允许的话,还是建议大家去购买收费版.支持原创作者,才能有更好的产品出现. 一.Jrebel插件介绍 JRebel一款帮助我们在开发过程中实现热加载的插件,目前来说,在IDEA中实现热加载最 ...

随机推荐

  1. 2019-11-29-WPF-模拟触摸设备

    原文:2019-11-29-WPF-模拟触摸设备 title author date CreateTime categories WPF 模拟触摸设备 lindexi 2019-11-29 08:47 ...

  2. SAP PI开发手册-ERP发布服务供外部系统调用(sproxy代理类)

    转自:https://www.cnblogs.com/fanjb/p/10829858.html 一.      接口内容 接口详细信息 1.  字段对应关系 发送字段对应关系 返回字段对应关系 2. ...

  3. WPF两个按钮来回切换样式

    <!-- 两个按钮来回切换样式 --> <Style x:Key="SwicthFunctionMetroToggleButton" TargetType=&qu ...

  4. vue中使用axios进行ajax请求数据(跨域配置)

    npm安装axios npm install axios --save 引入axios import axios from 'axios' 使用axios mounted () { this.getH ...

  5. [b0012] Hadoop 版hello word mapreduce wordcount 运行(二)

    目的: 学习Hadoop mapreduce 开发环境eclipse windows下的搭建 环境: Winows 7 64 eclipse 直接连接hadoop运行的环境已经搭建好,结果输出到ecl ...

  6. 7.InfluxDB-InfluxQL基础语法教程--INTO子句

    本文翻译自官网,官网地址:(https://docs.influxdata.com/influxdb/v1.7/query_language/data_exploration/) 通过INTO子句,可 ...

  7. 【原创】Talend 配置SSL支持gitlab

    背景 talend的源代码控制用的是gitlab,以前都是http方式的,但是最近突然改了https,所以talend登录失败,必须要SSL方式才能获取到分支等数据,才能提交代码. 证书导入 1.ta ...

  8. css 序

    盒模型 1.属性:width :内容的宽度 书写内容的宽度 height:内容的高度 书写内容的宽度 padding:内边框 内容到边框的距离  可以有  background-color borde ...

  9. 使用jmeter进行压力测试及如何添加负载机

    Jmeter是一款简单灵活且强大的性能测试工具,同时也可以做接口测试. 由于初识jmeter,今天来记录一下如何对一个web进行一个简单的压力测试. 1.首先在测试计划里面添加一个线程组,然后再其下面 ...

  10. CSRF/XSRF 跨站请求伪造

    CSRF/XSRF 跨站请求伪造 CSRF(Cross Site Request Forgery, 跨站域请求伪造)也称 XSRF, 是一种网络的攻击方式,它在 2007 年曾被列为互联网 20 大安 ...