基于JRebel开发的MybatisPlus热加载插件

原文链接https://githuboy.online/2019/05/11/%E5%9F%BA%E4%BA%8EJRebel%E5%BC%80%E5%8F%91%E7%9A%84MybatisPlus%E7%83%AD%E5%8A%A0%E8%BD%BD%E6%8F%92%E4%BB%B6/

前言

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

探索

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

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

按照官网配置

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

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

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

最终定位到关键代码

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

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

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

开搞

先来个滑稽压压惊

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

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

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

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

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

插件下载地址

如何使用请阅读README.md

总结

  • 学习了javaassit的使用.

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

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

### 回答1: jrebel mybatisplus extension是一个JRebel插件,用于支持Mybatis Plus框架的部署。Mybatis Plus是一个基于Mybatis的增强工具,可以简化Mybatis开发流程,提高开发效率。使用jrebel mybatisplus extension可以在开发过程中实现代码的部署,不需要重启应用程序,可以快速地查看代码的变化效果。 ### 回答2: JRebel 是一款 Java 实时部署工具。它可以在不重新启动应用程序的情况下重新加载代码,以加快开发周期。 Mybatis-Plus 是一个 Mybatis 框架的增强工具包,提供了许多易于使用的功能,如通用 Mapper,分页插件等。这两个工具结合起来使用可以更进一步提高开发效率。 JRebel Mybatis-Plus Extension 是一个为了方便开发者在使用JRebel插件时对Mybatis-Plus框架做一些支持的扩展。该扩展支持了 Mybatis-Plus 相关的类进行重新加载,从而让开发更加高效。具体来说,这个插件可以解决开发者在使用Mybatis-Plus时遇到的包括但不限于实体类字段名修改、XML配置文件修改、Mapper 方法修改等问题。 该插件的使用方式也很简单,在项目中添加相应的依赖后,在IDEA 或 Eclipse 中启用 JRebel 插件,就可以实现 Mybatis-Plus 对象的实时重载。这个插件也提供了一些配置选项来确保它能够在各种不同的项目环境中运行。 总之,JRebel Mybatis-Plus Extension 让开发者们无需频繁的重启服务,即可快速地调试和更新项目代码,从而更加高效地完成开发任务。 ### 回答3: JRebel是一个Java开发者工具,它可以在不重新启动应用程序的情况下重新加载Java类和资源文件。这样可以加快开发和调试过程,提高开发效率。而MyBatis-Plus是一个简化了MyBatis操作的框架,它提供了一些方便的功能,例如自动生成SQL、分页插件等。 JRebelMyBatis-Plus的结合体JRebel MyBatis-Plus Extension就是针对MyBatis-Plus框架开发JRebel扩展插件。它可以使MyBatis-Plus框架的Mapper、Service、Controller等代码的变更实时生效,无需重启应用程序。JRebel MyBatis-Plus Extension的使用可以大大提高开发效率,减少等待时间,特别是在开发大型项目时尤为重要。 使用JRebel MyBatis-Plus Extension还需要安装JRebel插件MyBatis-Plus框架。在项目中引入JRebel MyBatis-Plus Extension后,只需要将其配置到JRebel插件中,就可以随时实时更新应用程序的代码了。 总的来说,JRebel MyBatis-Plus Extension是一个非常有用的工具,可以协助开发者提高开发效率,减少等待时间。如果你正在开发使用MyBatis-Plus框架的Java应用程序,那么JRebel MyBatis-Plus Extension可以让你更轻松愉快地完成开发工作。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值