您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 质量控制/管理 > 优化与扩展Mybatis的SqlMapper解析
优化与扩展Mybatis的SqlMapper解析一、Mybatis全局配置Mybatis的全局配置,对应内存对象为Configuration,是重量级对象,和数据源DataSource、会话工厂SqlSessionFactory属于同一级别,一般来说(单数据源系统)是全局单例。从SqlSessionFactoryBean的doGetConfigurationWrapper()方法可以看到,有三种方式构建,优先级依次为:1.spring容器中注入,由用户直接注入一个Configuration对象2.根据mybatis-config.xml中加载,而mybatis-config.xml的路径由configLocation指定,配置文件使用组件XMLConfigBuilder来解析3.采用mybatis内部默认的方式,直接new一个配置对象Configuration这里为了简单,偷一个懒,不具体分析XMLConfigBuilder了,而直接采用spring中注入的方式,这种方式也给了扩展Configuration一个极大的自由。二、读取所有SqlMapper.xml配置文件也有两种方式,一种是手工配置,一种是使用自动扫描。推荐的自然是自动扫描,就不多说了。加载所有SqlMapper.xml配置文件之后就是循环处理每一个文件了。三、解析单个SqlMapper.xml配置文件单个SqlMapper.xml文件的解析入口是SqlSessionFactoryBean的doParseSqlMapperResource()方法,在这个方法中,自动侦测是DTD还是XSD,然后分两条并行路线分别解析:1、DTD模式:创建XMLMapperBuilder对象进行解析2、XSD模式:根据ini配置文件,找到sqlmapper命名空间的处理器SchemaSqlMapperNamespaceParser,该解析器将具体的解析工作委托给SchemaSqlMapperParserDelegate类。四、解析Statement级元素Statement级元素指的是根元素mapper的一级子元素,这些元素有cache|cache-ref|resultMap|parameterMap|sql|insert|update|delete|select,其中insert|update|delete|select就是通常所说的增删改查,用于构建mybatis一次执行单元,也就是说,每一次mybatis方法调用都是对insert|update|delete|select元素的一次访问,而不能说只访问select的某个下级子元素;其它的一级子元素则是用于帮助构建执行单元(resultMap|parameterMap|sql)或者影响执行单元的行为的(cache|cache-ref)。所以一级子元素可以总结如下:执行单元元素:insert|update|delete|select单元辅助元素:resultMap|parameterMap|sql执行行为元素:cache|cache-ref这些元素是按如下方式解析的:1、DTD模式:使用XMLMapperBuilder对象内的方法分别解析上面负责解析的每行代码都是一个内部方法,比如解析select|insert|update|delete元素的方法:可以看到,具体解析又转给XMLStatementBuilder了,而最终每一个select|insert|update|delete元素在内存中表现为一个MappedStatement对象。2、XSD模式:这里引入一个Statement级元素解析接口IStatementHandlerpublicinterfaceIStatementHandler{voidhandleStatementNode(Configurationconfiguration,SchemaSqlMapperParserDelegatedelegate,XNodenode);}每个实现类负责解析一种子元素,原生元素对应实现类有:然后创建一个注册器类SchemaHandlers来管理这些实现类。这个过程主要有两步:(1)应用启动时,将IStatementHandler的实现类和对应命名空间的相应元素事先注册好复制代码//静态代码块,注册默认命名空间的StatementHandlerregister(cache-ref,newCacheRefStatementHandler());register(cache,newCacheStatementHandler());register(parameterMap,newParameterMapStatementHandler());register(resultMap,newResultMapStatementHandler());register(sql,newSqlSta());register(select|insert|update|delete,newCRUDStatementHandler());复制代码(2)在解析时,根据XML中元素的命名空间和元素名,找到IStatementHandler的实现类,并调用接口方法ViewCode这样,只要事先编写好IStatementHandler的实现类,并调用SchemaHandlers的注册方法,解析就能顺利进行,而不管是原生的元素,还是自定义命名空间的扩展元素。举个例子,和select|insert|update|delete对应的实现类如下:ViewCode这里,也将具体解析转给XMLStatementBuilder了,只不过这里不是直接new对象,而是通过工厂类创建而已。五、LanguageDriver从上面知道DTD和XSD又汇集到XMLStatementBuilder了,而在这个类里面,间接的创建了LanguageDriver的实现类,用来解析脚本级的SQL文本和元素,以及处理SQL脚本中的参数。LanguageDriver的作用实际上就是组件工厂,和我们的ISqlSessionComponentFactory类似:复制代码publicinterfaceLanguageDriver{/***创建参数处理器*/ParameterHandlercreateParameterHandler(MappedStatementmappedStatement,ObjectparameterObject,BoundSqlboundSql);/***根据XML节点创建SqlSource对象*/SqlSourcecreateSqlSource(Configurationconfiguration,XNodescript,Class?parameterType);/***根据注解创建SQLSource对象*/SqlSourcecreateSqlSource(Configurationconfiguration,Stringscript,Class?parameterType);}复制代码这里因为要再次区分DTD和XSD,需要使用我们自己的实现类,并在Configuration里面配置,又因为是使用XML配置,所以第三个方法就不管了:复制代码publicclassSchemaXMLLanguageDriverextendsXMLLanguageDriver{//返回ExpressionParameterHandler,可以处理表达式的参数处理器@OverridepublicParameterHandlercreateParameterHandler(MappedStatementmappedStatement,ObjectparameterObject,BoundSqlboundSql){returnSqlSessionComponetFactorys.newParameterHandler(mappedStatement,parameterObject,boundSql);}//如果是DTD,则使用XMLScriptBuilder,否则使用SchemaXMLScriptBuilder,从而再次分开处理@OverridepublicSqlSourcecreateSqlSource(Configurationconfiguration,XNodescript,Class?parameterType){XMLScriptBuilderbuilder=SqlSessionComponetFactorys.newXMLScriptBuilder(configuration,script,parameterType);returnbuilder.parseScriptNode();}}复制代码六、解析Script级元素Script级元素指的是除根元素和一级子元素之外的元素(当然也不包括注释元素了。。。),是用来构建Statement级元素的,包括SQL文本和动态配置元素(include|trim|where|set|foreach|choose|if),这些元素按如下方式解析:1、DTD模式:使用XMLScriptBuilder解析,这里mybatis倒是使用了一个解析接口,可惜的是内部的私有接口,并且在根据元素名称获取接口实现类时也是莫名其妙(竟然每次获取都先创建所有的实现类,然后返回其中的一个,这真是莫名其妙的一塌糊涂!):另外,SQL文本则是使用TextSqlNode解析。2、XSD模式:和Statement级元素类似,这里引入一个Script级元素解析接口IScriptHandlerpublicinterfaceIScriptHandler{voidhandleScriptNode(Configurationconfiguration,XNodenode,ListSqlNodetargetContents);}每个实现类负责解析一种子元素,也使用SchemaHanders来管理这些实现类。具体也是两个步骤:(1)静态方法中注册复制代码//注册默认命名空间的ScriptHandlerregister(trim,newTrimScriptHandler());register(where,newWhereScriptHandler());register(set,newSetScriptHandler());register(foreach,newForEachScriptHandler());register(if|when,newIfScriptHandler());register(choose,newChooseScriptHandler());//register(when,newIfScriptHandler());register(otherwise,newOtherwiseScriptHandler());register(bind,newBindScriptHandler());复制代码(2)在使用SchemaXMLScriptBuilder解析时根据元素命名空间和名称获取解析器复制代码publicstaticListSqlNodeparseDynamicTags(Configurationconfiguration,XNodenode){ListSqlNodecontents=newArrayListSqlNode();NodeListchildren=node.getNode().getChildNodes();for(inti=0;ichildren.getLength();i++){XNodechild=node.newXNode(children.item(i));shortnodeType=child.getNode().getNodeType();if(nodeType==Node.CDATA_SECTIO
本文标题:优化与扩展Mybatis的SqlMapper解析
链接地址:https://www.777doc.com/doc-2718838 .html