mybatis源码-解析配置文件(二)之解析的流程

在之前的文章《mybatis 初步使用(IDEA的Maven项目, 超详细)》中, 讲解了mybatis的初步使用, 并总结了以下mybatis的执行流程:

通过 Resources 工具类读取 mybatis-config.xml, 存入 Reader;

SqlSessionFactoryBuilder 使用上一步获得的 reader 创建 SqlSessionFactory 对象;

通过 sqlSessionFactory 对象获得 SqlSession;

SqlSession对象通过 *Mapper 方法找到对应的 SQL 语句, 执行 SQL 查询。

底层通过 JDBC 查询后获得 ResultSet, 对每一条记录, 根据resultMap的映射结果映射到 Student 中, 返回 List。

最后记得关闭 SqlSession

本系列文章深入讲解第 2 步, 解析配置文件。

2. 配置文件解析流程分析 2.1 调用

配置文件的解析过程对应的是以下的代码:

Reader reader = Resources.getResourceAsReader("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

很简单的两句代码:

通过mybatis的资源类Resources读入“mybatis-config.xml”文件;

使用SqlSessionFactoryBuilder类生成我们需要的SqlSessionFactory类;(真正的解析只有这一过程)

2.2 解析的目的

要理解配置文件的解析过程, 首先要明白解析的目的是什么, 从最直观的调用代码来看, 是获得SqlSessionFactory。

但是, 从源代码来看, 更本质的应该这么说:

mybatis解析配置文件最本质的目的是为了获得Configuration对象

Configuration 对象, 可以理解是mybatis的XML文件在程序中的化身。

2.3 XML 解析流程

build(reader)函数里面包含着SqlSessionFactory的创建逻辑。

从客户端调用build(reader)函数到返回SqlSessionFactory, 可以用如下的时序图表示:

解析时序图

下面来看看各个步骤, 请记住,mybatis解析配置文件的本质就是获得Configuration对象

2.3.1 build(parser)

其最终调用以下的方法

public SqlSessionFactory build(Reader reader, String environment, Properties properties) { try { XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties); return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { reader.close(); } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } }

该方法:

创建XMLConfigBuilder对象;

使用XMLConfigBuilder对象的方法parse()来获得Confiuration对象;

通过build(configuration), 使用Confiuration对象创建相应的SqlSessionFactory对象。

2.3.2 new XMLConfigBuilder(...);

new XMLConfigBuilder(reader, environment, properties)方法, 从字面上来理解就是创建一个XMLConfigBuilder对象。

public XMLConfigBuilder(Reader reader, String environment, Properties props) { this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props); }

其最终调用的方法是这个:

private XMLConfigBuilder(XPathParser parser, String environment, Properties props) { super(new Configuration()); ErrorContext.instance().resource("SQL Mapper Configuration"); this.configuration.setVariables(props); this.parsed = false; this.environment = environment; this.parser = parser; }

XMLConfigBuilder类继承于BaseBuilder类, super(new Configuration())对应的方法:

public BaseBuilder(Configuration configuration) { this.configuration = configuration; this.typeAliasRegistry = this.configuration.getTypeAliasRegistry(); this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry(); }

也就是给BaseBuilder类的各个成员变量赋值而已。

里面的XpathParser对象是通过new XPathParser(reader, true, props, new XMLMapperEntityResolver())方法而来的。

2.3.3 new XPathParser(...)

new XPathParser(reader, true, props, new XMLMapperEntityResolver())就是创建XpathParser的过程。

public XPathParser(Reader reader, boolean validation, Properties variables, EntityResolver entityResolver) { commonConstructor(validation, variables, entityResolver); this.document = createDocument(new InputSource(reader)); }

调用了以下两个函数:

private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) { this.validation = validation; this.entityResolver = entityResolver; this.variables = variables; XPathFactory factory = XPathFactory.newInstance(); this.xpath = factory.newXPath(); } private Document createDocument(InputSource inputSource) { // important: this must only be called AFTER common constructor try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(validation); factory.setNamespaceAware(false); factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(false); factory.setCoalescing(false); factory.setExpandEntityReferences(true); DocumentBuilder builder = factory.newDocumentBuilder(); builder.setEntityResolver(entityResolver); builder.setErrorHandler(new ErrorHandler() { @Override public void error(SAXParseException exception) throws SAXException { throw exception; } @Override public void fatalError(SAXParseException exception) throws SAXException { throw exception; } @Override public void warning(SAXParseException exception) throws SAXException { } }); return builder.parse(inputSource); } catch (Exception e) { throw new BuilderException("Error creating document instance. Cause: " + e, e); } }

注意这两个函数是有先后顺序的, createDocument函数务必在commonConstructor函数之后执行

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjdyy.html