优化与扩展Mybatis的SqlMapper解析.doc_第1页
优化与扩展Mybatis的SqlMapper解析.doc_第2页
优化与扩展Mybatis的SqlMapper解析.doc_第3页
优化与扩展Mybatis的SqlMapper解析.doc_第4页
优化与扩展Mybatis的SqlMapper解析.doc_第5页
已阅读5页,还剩2页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

优化与扩展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级元素指的是根元素的一级子元素,这些元素有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级元素解析接口IStatementHandlerpublic interface IStatementHandler void handleStatementNode(Configuration configuration, SchemaSqlMapperParserDelegate delegate, XNode node);每个实现类负责解析一种子元素,原生元素对应实现类有:然后创建一个注册器类SchemaHandlers来管理这些实现类。这个过程主要有两步:(1)应用启动时,将IStatementHandler的实现类和对应命名空间的相应元素事先注册好复制代码/静态代码块,注册默认命名空间的StatementHandlerregister(cache-ref, new CacheRefStatementHandler();register(cache, new CacheStatementHandler();register(parameterMap, new ParameterMapStatementHandler();register(resultMap, new ResultMapStatementHandler();register(sql, new SqlStementHandler();register(select|insert|update|delete, new CRUDStatementHandler();复制代码(2)在解析时,根据XML中元素的命名空间和元素名,找到IStatementHandler的实现类,并调用接口方法 View Code这样,只要事先编写好IStatementHandler的实现类,并调用SchemaHandlers的注册方法,解析就能顺利进行,而不管是原生的元素,还是自定义命名空间的扩展元素。举个例子,和select|insert|update|delete对应的实现类如下: View Code这里,也将具体解析转给XMLStatementBuilder了,只不过这里不是直接new对象,而是通过工厂类创建而已。五、LanguageDriver从上面知道DTD和XSD又汇集到XMLStatementBuilder了,而在这个类里面,间接的创建了LanguageDriver的实现类,用来解析脚本级的SQL文本和元素,以及处理SQL脚本中的参数。LanguageDriver的作用实际上就是组件工厂,和我们的ISqlSessionComponentFactory类似:复制代码public interface LanguageDriver /* * 创建参数处理器*/ ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql); /* * 根据XML节点创建SqlSource对象 */ SqlSource createSqlSource(Configuration configuration, XNode script, Class parameterType); /* * 根据注解创建SQLSource对象 */ SqlSource createSqlSource(Configuration configuration, String script, Class parameterType);复制代码这里因为要再次区分DTD和XSD,需要使用我们自己的实现类,并在Configuration里面配置,又因为是使用XML配置,所以第三个方法就不管了:复制代码public class SchemaXMLLanguageDriver extends XMLLanguageDriver / 返回ExpressionParameterHandler,可以处理表达式的参数处理器 Override public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) return SqlSessionComponetFactorys.newParameterHandler(mappedStatement, parameterObject, boundSql); / 如果是DTD,则使用XMLScriptBuilder,否则使用SchemaXMLScriptBuilder,从而再次分开处理 Override public SqlSource createSqlSource(Configuration configuration, XNode script, Class parameterType) XMLScriptBuilder builder = SqlSessionComponetFactorys.newXMLScriptBuilder(configuration, script, parameterType); return builder.parseScriptNode(); 复制代码六、解析Script级元素Script级元素指的是除根元素和一级子元素之外的元素(当然也不包括注释元素了。),是用来构建Statement级元素的,包括SQL文本和动态配置元素(include|trim|where|set|foreach|choose|if),这些元素按如下方式解析:1、DTD模式:使用XMLScriptBuilder解析,这里mybatis倒是使用了一个解析接口,可惜的是内部的私有接口,并且在根据元素名称获取接口实现类时也是莫名其妙(竟然每次获取都先创建所有的实现类,然后返回其中的一个,这真是莫名其妙的一塌糊涂!):另外,SQL文本则是使用TextSqlNode解析。2、XSD模式:和Statement级元素类似,这里引入一个Script级元素解析接口IScriptHandlerpublic interface IScriptHandler void handleScriptNode(Configuration configuration, XNode node, List targetContents);每个实现类负责解析一种子元素,也使用SchemaHanders来管理这些实现类。具体也是两个步骤:(1)静态方法中注册复制代码/注册默认命名空间的ScriptHandlerregister(trim, new TrimScriptHandler();register(where, new WhereScriptHandler();register(set, new SetScriptHandler();register(foreach, new ForEachScriptHandler();register(if|when, new IfScriptHandler();register(choose, new ChooseScriptHandler();/register(when, new IfScriptHandler();register(otherwise, new OtherwiseScriptHandler();register(bind, new BindScriptHandler();复制代码(2)在使用SchemaXMLScriptBuilder解析时根据元素命名空间和名称获取解析器复制代码public static List parseDynamicTags(Configuration configuration, XNode node) List contents = new ArrayList(); NodeList children = node.getNode().getChildNodes(); for (int i = 0; i children.getLength(); i+) XNode child = node.newXNode(children.item(i); short nodeType = child.getNode().getNodeType(); if (nodeType = Node.CDATA_SECTION_NODE | nodeType = Node.TEXT_NODE) String data = getStringBody(); data = decorate(configuration.getDatabaseId(), data);/对SQL文本进行装饰,从而嵌入SQL配置函数的处理 ExpressionTextSqlNode expressionTextSqlNode = new ExpressionTextSqlNode(data);/使用表达式SQL文本,从而具有处理表达式的能力 if (expressionTextSqlNode.isDynamic() contents.add(expressionTextSqlNode); setDynamic(true); else contents.add(new StaticTextSqlNode(data); else if (nodeType = Node.ELEMENT_NODE) / issue / #628 IScriptHandler handler = SchemaHandlers.getScriptHandler(child.getNode();/使用处理器机制,从而可以方便、自由地扩展 if (handler = null) throw new BuilderException(Unknown element in SQL statement.); handler.handleScriptNode(configuration, child, contents); setDynamic(true); return contents;复制代码七、处理fnnameargs、fnnameargs、(exp)和#(exp)这里引进了两个概念来扩展mybatis的配置:1、SQL配置函数(1)SQL配置函数,只用于配置SQL文本,和SQL函数不同,SQL函数是在数据库中执行的,而SQL配置函数只是JAVA中生成SQL脚本时候解析(2)SQL配置函数形如 $fn_nameargs,其中函数名是字母或下划线开头的字母数字下划线组合,不能为空(为空则是mybatis原生的字符串替换语法)(3)SQL配置函数在mybatis加载时解析一次,并将解析结果存储至SqlNode对象中,不需要每次运行都解析(4)SQL配置函数的定义和解析接口ISqlConfigFunction如下:复制代码public interface ISqlConfigFunction /* * 优先级,如果有多个同名函数,使用order值小的 * return */ public int getOrder(); /* * 函数名称 * return */ public String getName(); /* * 执行SQL配置函数 * param databaseId 数据库ID * param args 字符串参数 * return */ public String eval(String databaseId, String args);复制代码(5)SQL配置函数的设别表达式如下(匆匆写就,尚未测试充分)(6)ISqlConfigFunction也使用SchemaHandlers统一注册和管理。(7)SQL配置函数名不区分大小写,但参数区分大小写。2

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论