前天項目中使用了mybatis-plus,可是搭配Jrebel開發項目時,發現修改mapper的xml,或者mapper方法中的註解,Jrebel並無可以reload mapper.因而就有了本篇文章html
爲了解決這個問題,首先想到的是到mybatis-plus官網查看配置方法,官網中的文檔熱加載很清楚說明了java
3.0.6版本上移除了該功能,不過最新快照版已加回來並打上廢棄標識,3.1.0版本上已徹底移除
git
按照官網配置github
@Bean @Profile("dev") // public MybatisMapperRefresh mybatisMapperRefresh (MybatisPlusProperties properties, SqlSessionFactory sessionFactory){ return new MybatisMapperRefresh(properties.resolveMapperLocations(), sessionFactory, true); }
上述配置後從新運行項目,修改mapper,發現並無生效,因而開始研究他的源碼。
經過查看MybatisMapperRefresh
源碼發現他的實現方式:重建mapper來實現熱加載
的。spring
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(resource.getInputStream(), sqlSessionFactory.getConfiguration(), resource.toString(), sqlSessionFactory.getConfiguration().getSqlFragments()); xmlMapperBuilder.parse();
最終定位到關鍵代碼sql
/** * MybatisPlus 加載 SQL 順序: * <p>一、加載XML中的SQL</p> * <p>二、加載sqlProvider中的SQL</p> * <p>三、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)的緣由之一apache
上面添加MappedStatement
到Configuration
時先判斷了是否已經加載過,可是項目啓動時,Configuration
已加載了全部的MappedStatement
,因此MybatisMapperRefresh
這個後臺線程後面reload徹底沒有做用.session
爲了弄清楚JRebel是如何實現mybatis熱加載。mybatis
我把jrebel的插件做爲libary,添加到工程裏.app
利用IDEA 自然的反編譯功能,順利成章的看到了源碼
下面是mybatis熱加載插件的主入口
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類。
而後趁IDEA不注意的時候,去Jrebel的官網找到了開發自定義插件的文檔Custom JRebel plugins.
最終寫了這個插件。
PS:其中大部分的代碼來自原插件反編譯後代碼,同時結合Mybatis-plus重寫的源碼,作了相應適配.
下面是插件源碼地址:
下面是插件下載地址:
如何使用請閱讀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熱加載插件/