Mybatis-Plus(简称MP)是一款Mybatis增强工具,那么它是如何增强的呢?其实它已经封装了一些crud方法,所以开发不需要写xml,直接调用这些方法即可,类似JPA。那么在这篇文章中,我们就来看看下面MP的具体实现,看看是如何实现这些增强的。入口类:MybatisSqlSessionFactoryBuilder在入口类MybatisSqlSessionFactoryBuilder#build方法中,当应用程序启动时,将mybatisplus(简称MP)自定义的动态配置xml文件注入到Mybatis中。公共类mybatissqlSessionFactoryBuilder扩展了SQLSessionFactoryBuilder{publicSqlSessionFactorybuild(configurationconfiguration){//...省略if(globalconfig.isenablesqlrunner())}//...省略若干行returnsqlSessionFactory;}}这里涉及到2个MP2功能类,扩展继承自Mybatis的MybatisConfiguration类:MP动态脚本构建、注册等逻辑判断。SqlRunnerInjector:MP默认为一些动态方法插入xml脚本方法。MybatisConfiguration类这里重点分析MybatisConfiguration类。在MybatisConfiguration中,MP初始化了自己的MybatisMapperRegistry,MybatisMapperRegistry是MP加载自定义SQL方法的注册器。MybatisConfiguration中的很多方法都是使用MybatisMapperRegistry重写的。其中,实现注册MP动态脚本功能的重载方法addMapper有3个。publicclassMybatisConfigurationextendsConfiguration{/***Mapper注册*/protectedfinalMybatisMapperRegistrymybatisMapperRegistry=newMybatisMapperRegistry(this);//..../***初始化调用*/publicMybatisConfiguration(){super();这。mapUnderscoreToCamelCase=true;languageRegistry.setDefaultDriverClass(MybatisXMLLanguageDriver.class);}/***MybatisPlusloadSQLsequence:*vid*
1.LoadSQLinXML
*Pro
2.LoaderSQL/p>*
3.XmlSql和SqlProvider不能包含相同的SQL
*
调整SQL优先级:XmlSql>sqlProvider>CurdSql
*/@OverridepublicvoidaddMappedStatement(MappedStatementms){//...}}//...省略几行/***使用你自己的MybatisMapperRegistry*/@Overridepublic
voidaddMapper(Classtype){addMapmybatisMapperRegistry(type);添加MapmybatisMapperRegistry。}//....省略几行}在MybatisMapperRegistry中,MP将mybatis的MapperAnnotationBuilder替换为MP自己的MybatisMapperAnnotationBuilderpublicclassMybatisMapperRegistryextendsMapperRegistry{@OverridepublicvoidaddMapper(Classtype){//...linesMybatisMapperAnnotationBuilderparser=newMybatisMapperAnnotationBuilder(config,type);解析器.parse();//...省略几行}}在MybatisMapperRegistry类的addMapper方法中,真正进入MP的核心类MybatisMapperAnnotationBuilder是MybatisMapperAnnotationBuilder。MP实现动态脚本关键类MybatisMapperAnnotationBuilderisdynamicallyconstructedintheparsermethodofMybatisMapperAnnotationBuilder,thecoreclassofMP.MPtraversestheMapperclassestobeloadedonebyone.TheloadingmethodsincludethefollowingpublicclassMybatisMapperAnnotationBuilderextendsMapperAnnotationBuilder{@Overridepublicvoidparse(){//...Omitted若干行?????????for?(Method?method?:?type.getMethods())?{????????????/**?for循环代码,?MP判断method方法是否是@Select?@Insert等mybatis注解方法**/????????????parseStatement(method);????????????InterceptorIgnoreHelper.initSqlParserInfoCache(cache,?mapperName,?method);????????????SqlParserHelper.initSqlParserInfoCache(mapperName,?method);????????}????????/**?这2行代码,?MP注入默认的方法列表**/????????if?(GlobalConfigUtils.isSupperMapperChildren(configuration,?type))?{????????????GlobalConfigUtils.getSqlInjector(configuration).inspectInject(assistant,type);}}//...omitseverallines}@OverridepublicvoidinspectInject(MapperBuilderAssistantbuilderAssistant,Class>mapperClass){Class>modelClass=extractModel类(映射器类);//...省略几行ListmethodList=this.getMethodList(mapperClass);TableInfotableInfo=TableInfoHelper.initTableInfo(builderAssistant,modelClass);->m.inject(builderAssistant,mapperClass,modelClass,tableInfo));mapperRegistryCache.add(className);}}公共类DefaultSqlInjector扩展AbstractSqlInjector{@OverridepublicListgetMethodList(Class>mapperClass){返回Stream。of(newInsert(),//...省略几行newSelectPage()).collect(toList());}}在MybatisMapperAnnotationBuilder中,MP实际上是将框架自定义的动态SQL语句注册到Mybatis引擎中,AbstractMethod实现了具体方法的SQL语句构造。具体AbstractMethod实例类,构造具体方法SQL语句,以SelectById类为例说明/***根据ID查询一条数据*/publicclassSelectByIdextendsAbstractMethod{@OverridepublicMappedStatementinjectMappedStatement(Class>mapperClass,Class>modelClass,TableInfotableInfo){/**定义mybatisxml方法id,对应**/SqlMethodsqlMethod=SqlMethod.SELECT_BY_ID;/**构造对应id的具体xml片段**/SqlourcesqlSource=newRawSqlSource(configuration,String.format(sqlMethod.getSql(),sqlSelectColumns(tableInfo,false),tableInfo.getTableName(),tableInfo.getKeyColumn(),tableInfo.getKeyProperty(),tableInfo.getLogicDeleteSql(true,true)),Object.class);/**将xml方法方法添加到mybatis的MappedStatement中**/returnthis.addSelectMappedStatementForTable(mapperClass,getMethod(sqlMethod),sqlSource,tableInfo);}}至此,MP在启动时完成了加载自定义方法xml配置的过程,接下来是mybatis${variable}#{variable}的动态替换预编译,进入了mybatis自身的功能。综上所述,MP总共对mybatis的十多个类进行了改写和替换,主要如下图所示:总体来说,MP实现了对mybatis的增强,手段略显繁琐,不够直观。实际上,自定义方法的XML文件是根据mybatismapperantationBuilder构建的。地图位置;@OverridepublicvoidsetMapperLocations(Resource...mapperLocations){super.setMapperLocations(mapperLocations);/**暂存mybatis原来定义的mapperxml文件路径**/this.mapperLocations=mapperLocations;ConfigurableListableBeanFactorybeanFactory=getBeanFactory();/**只需要在xml资源中注入自定义方法,在mybatis中注入原生定义的Resource,就可以实现MP的自定义动态SQL和原生SQL的共生关系**/this.setMapperLocations(InjectMapper.getMapperResource(this.dbType,beanFactory,this.mapperLocations));超级后rPropertiesSet();}}在这篇文章中,我们简单介绍了MP实现动态语句的实现过程,并给出了一种可能更方便的方法