欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

mybatis_3源码阅读日记_容器的加载与初始化

程序员文章站 2022-03-25 10:57:11
SqlSessionFactory的创建SqlSessionFactory是通过SqlSessionFactoryBuilder工厂类创建的,而不是直接使用构造器。SqlSessionFactoryBuilder的主要代码如下: //SqlSessionFactoryBuilder是一个建造者模式 public SqlSessionFactory build(InputStream inputStream) { return build(inputStream, null, null);...

MyBatis整体架构

Mybatis的功能架构分为三层
API接口层,数据处理层,基础支持层

API接口层

核心对象就是SqlSession,它是上层应用和Mybatis打交道的桥梁,也有的人称之为大门,SqlSession中定义了非常多的对数据库操作的方法,接口层在接受到调用请求时,会调用核心处理层的相应模块来完成具体的数据库操作

数据处理层

这一层主要就是跟数据库操作相关的动作都是在这数据处理层完成的。
核心处理层主要做了这4件事:

  • 把接口中传入的参数解析并映射成JDBC类型;
  • 解析xml文件中的SQL语句,包括插入参数和动态SQL的生成;
  • 执行SQL语句;
  • 处理结果集,并映射成Java对象。

插件也属于核心层,这是由它的工作方式和拦截的对象决定的。

基础支撑层

负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。
mybatis_3源码阅读日记_容器的加载与初始化
mybatis_3源码阅读日记_容器的加载与初始化

MyBatis的主要成员

Configuration

MyBatis所有的配置信息都保存在Configuration对象之中,配置文件中的大部分配置都会存储到该类中。

SqlSession

作为MyBatis工作的主要顶层API,表示和数据库交互时的会话,完成必要数据库增删改查功能。

Executor

MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护。

StatementHandler

封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数等。

ParameterHandler

负责对用户传递的参数转换成JDBC Statement 所对应的数据类型。

ResultSetHandler

负责将JDBC返回的ResultSet结果集对象转换成List类型的集合。

TypeHandler

负责java数据类型和jdbc数据类型(也可以说是数据表列类型)之间的映射和转换。

MappedStatement

MappedStatement维护一条<select|update|delete|insert>节点的封装。

SqlSource

负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回

BoundSql

表示动态生成的SQL语句以及相应的参数信息。

SqlSessionFactory的创建

SqlSessionFactory是通过SqlSessionFactoryBuilder工厂类创建的,而不是直接使用构造器。
SqlSessionFactoryBuilder的主要代码如下:

 //SqlSessionFactoryBuilder是一个建造者模式
 public SqlSessionFactory build(InputStream inputStream) {
    return build(inputStream, null, null);
  }
  
 public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }
 
 public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

SqlSessionFactory提供了根据字节流、字符流以及直接使用org.apache.ibatis.session.Configuration配置类(后续我们会详细讲到)三种途径的读取配置信息方式,但究其根本都是首先将XML配置文件构建为Configuration配置类,然后将Configuration设置到SqlSessionFactory默认实现DefaultSqlSessionFactory的configurationz字段并返回。主要解析配置文件的逻辑都委托给XMLConfigBuilder了。
XMLConfigBuilder的主要代码

public class XMLConfigBuilder extends BaseBuilder {
	....
	  /**
	   * Description 构造XMLConfigBuilder
	   * @param reader 流
	   * @param environment 
	   * @param props
	   * @author songhongwei s19744
	  * @time 202/1/5 16:44
	   **/
	  public XMLConfigBuilder(Reader reader, String environment, Properties props) {
	    //XPathParser用于SAX解析xml,解析器硬编码为XMLMapperEntityResolver
	    this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
	  }
	  private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
	    //创建Configuration对象,用来保存配置文件的配置
	    super(new Configuration());
	    ErrorContext.instance().resource("SQL Mapper Configuration");
	    this.configuration.setVariables(props);
	    this.parsed = false;
	    this.environment = environment;
	    this.parser = parser;
	  }
	....
}

标签解析类

public class XPathParser {
 private final Document document;
 private boolean validation;
 //XML标签解析器,可使用不通的解析器,通过构造方法传进来,使用到了策略模式
 private EntityResolver entityResolver;
 private Properties variables;
 private XPath xpath;
    /**
    * Description 构造方法
    *
    * @param reader
    *            Reader
    * @param validation
    *            是否进行DTD 校验
    * @param variables
    *            属性配置
    * @param entityResolver 
    *            XML实体节点解析器
    * @author songhongwei s19744
    * @time 202/1/5 19:54
    **/
 public XPathParser(Reader reader, boolean validation, Properties variables, EntityResolver entityResolver) {
   commonConstructor(validation, variables, entityResolver);
   this.document = createDocument(new InputSource(reader));
 }
 
 //创建document
 private Document createDocument(InputSource inputSource) {
   // important: this must only be called AFTER common constructor
   try {
     DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
     factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
     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 {
         // NOP
       }
     });
     return builder.parse(inputSource);
   } catch (Exception e) {
     throw new BuilderException("Error creating document instance.  Cause: " + e, e);
   }
 }
}

XMLConfigBuilder以及解析Mapper文件的XMLMapperBuilder都继承于BaseBuilder。他们对于XML文件本身技术上的加载和解析都委托给了XPathParser,最终用的是jdk自带的xml解析器而非第三方比如dom4j,底层使用了xpath方式进行节点解析。new XPathParser(reader, true, props, new XMLMapperEntityResolver())的参数含义分别是Reader,是否进行DTD 校验,属性配置,XML实体节点解析器。

entityResolver,跟Spring的XML标签解析器一样,有默认的解析器,也有自定义的,主要使用了策略模式,在这里mybatis硬编码为XMLMapperEntityResolver。
XMLMapperEntityResolver的定义如下:

package org.apache.ibatis.builder.xml;

import org.apache.ibatis.io.Resources;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import java.io.IOException;
import java.io.InputStream;
import java.util.Locale;

/**
 * Offline entity resolver for the MyBatis DTDs.
 *
 * @author Clinton Begin
 * @author Eduardo Macarron
 */
public class XMLMapperEntityResolver implements EntityResolver {

  private static final String IBATIS_CONFIG_SYSTEM = "ibatis-3-config.dtd";
  private static final String IBATIS_MAPPER_SYSTEM = "ibatis-3-mapper.dtd";
  private static final String MYBATIS_CONFIG_SYSTEM = "mybatis-3-config.dtd";
  private static final String MYBATIS_MAPPER_SYSTEM = "mybatis-3-mapper.dtd";

  private static final String MYBATIS_CONFIG_DTD = "org/apache/ibatis/builder/xml/mybatis-3-config.dtd";
  private static final String MYBATIS_MAPPER_DTD = "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd";

    /**
     * Converts a public DTD into a local one. 将公共的DTD转换为本地模式
     * @param publicId The public id that is what comes after "PUBLIC"
     * @param systemId The system id that is what comes after the public id.
     * @return The InputSource for the DTD
     * @throws org.xml.sax.SAXException If anything goes wrong
     */
  @Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException {
    try {
      if (systemId != null) {
        String lowerCaseSystemId = systemId.toLowerCase(Locale.ENGLISH);
        if (lowerCaseSystemId.contains(MYBATIS_CONFIG_SYSTEM) || lowerCaseSystemId.contains(IBATIS_CONFIG_SYSTEM)) {
          return getInputSource(MYBATIS_CONFIG_DTD, publicId, systemId);
        } else if (lowerCaseSystemId.contains(MYBATIS_MAPPER_SYSTEM) || lowerCaseSystemId.contains(IBATIS_MAPPER_SYSTEM)) {
          return getInputSource(MYBATIS_MAPPER_DTD, publicId, systemId);
        }
      }
      return null;
    } catch (Exception e) {
      throw new SAXException(e.toString());
    }
  }

 private InputSource getInputSource(String path, String publicId, String systemId) {
    InputSource source = null;
    if (path != null) {
      try {
        InputStream in = Resources.getResourceAsStream(path);
        source = new InputSource(in);
        source.setPublicId(publicId);
        source.setSystemId(systemId);
      } catch (IOException e) {
        // ignore, null is ok
      }
    }
    return source;
  }

}

mybatis解析的时候,引用了本地的DTD文件,和本类在同一个package下,其中的ibatis-3-config.dtd应该主要是用于兼容用途。在其中getInputSource(MYBATIS_CONFIG_DTD, publicId, systemId)的调用里面有两个参数publicId(公共标识符)和systemId(系统标示符),他们是XML 1.0规范的一部分,在mybatis中,systemId指定的是mybatis-3-config.dtd和ibatis-3-config.dtd
调用栈

build:64, SqlSessionFactoryBuilder (org.apache.ibatis.session)
-->build:77, SqlSessionFactoryBuilder (org.apache.ibatis.session)
	--><init>:89, XMLConfigBuilder (org.apache.ibatis.builder.xml)
		--><init>:127, XPathParser (org.apache.ibatis.parsing)
			-->createDocument:261, XPathParser (org.apache.ibatis.parsing)
				-->parse:339, DocumentBuilderImpl (com.sun.org.apache.xerces.internal.jaxp)
					-->parse:243, DOMParser (com.sun.org.apache.xerces.internal.parsers)
						-->parse:141, XMLParser (com.sun.org.apache.xerces.internal.parsers)
							-->parse:771, XML11Configuration (com.sun.org.apache.xerces.internal.parsers)
								-->parse:842, XML11Configuration (com.sun.org.apache.xerces.internal.parsers)
									-->scanDocument:505, XMLDocumentFragmentScannerImpl (com.sun.org.apache.xerces.internal.impl)
										-->next:602, XMLDocumentScannerImpl (com.sun.org.apache.xerces.internal.impl)
											-->next:959, XMLDocumentScannerImpl$PrologDriver (com.sun.org.apache.xerces.internal.impl)
												-->next:1045, XMLDocumentScannerImpl$DTDDriver (com.sun.org.apache.xerces.internal.impl)
													-->dispatch:1151, XMLDocumentScannerImpl$DTDDriver (com.sun.org.apache.xerces.internal.impl)
														-->resolveEntityAsPerStax:997, XMLEntityManager (com.sun.org.apache.xerces.internal.impl)
															-->resolveEntity:110, EntityResolverWrapper (com.sun.org.apache.xerces.internal.util)
																-->resolveEntity:58, XMLMapperEntityResolver (org.apache.ibatis.builder.xml)

未完待续

本文地址:https://blog.csdn.net/u010859650/article/details/112243451