MyBatis源码解析 - MyBatis初始化

我们主要从下面两个方面来分析MyBatis的初始化过程:
初始化做什么?
怎么初始化?

初始化做什么?

任何框架的初始化,无非是加载自己运行时所需要的配置信息,org.apache.ibatis.session下的Configuration类,即为Mybatis所有配置信息的容器类。
包括的配置信息有:

public class Configuration {

  protected Environment environment;

  protected boolean safeRowBoundsEnabled = false;
  protected boolean safeResultHandlerEnabled = true;
  protected boolean mapUnderscoreToCamelCase = false;
  protected boolean aggressiveLazyLoading = true;
  protected boolean multipleResultSetsEnabled = true;
  protected boolean useGeneratedKeys = false;
  protected boolean useColumnLabel = true;
  protected boolean cacheEnabled = true;
  protected boolean callSettersOnNulls = false;
  protected String logPrefix;
  protected Class  logImpl;
  protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
  protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
  protected Set lazyLoadTriggerMethods = new HashSet(Arrays.asList(new String[] { "equals", "clone", "hashCode", "toString" }));
  protected Integer defaultStatementTimeout;
  protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
  protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;

  protected Properties variables = new Properties();
  protected ObjectFactory objectFactory = new DefaultObjectFactory();
  protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
  // 用于mapper接口类型注册
  protected MapperRegistry mapperRegistry = new MapperRegistry(this);

  protected boolean lazyLoadingEnabled = false;
  protected ProxyFactory proxyFactory;

  protected String databaseId;
  /**
   * Configuration factory class.
   * Used to create Configuration for loading deserialized unread properties.
   *
   * @see Issue 300 (google code)
   */
  protected Class configurationFactory;

  protected final InterceptorChain interceptorChain = new InterceptorChain();
  protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();
  protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
  protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();

  protected final Map mappedStatements = new StrictMap("Mapped Statements collection");
  protected final Map caches = new StrictMap("Caches collection");
  protected final Map resultMaps = new StrictMap("Result Maps collection");
  protected final Map parameterMaps = new StrictMap("Parameter Maps collection");
  protected final Map keyGenerators = new StrictMap("Key Generators collection");

  protected final Set loadedResources = new HashSet();
  protected final Map sqlFragments = new StrictMap("XML fragments parsed from previous mappers");

  protected final Collection incompleteStatements = new LinkedList();
  protected final Collection incompleteCacheRefs = new LinkedList();
  protected final Collection incompleteResultMaps = new LinkedList();
  protected final Collection incompleteMethods = new LinkedList();

  /*
   * A map holds cache-ref relationship. The key is the namespace that
   * references a cache bound to another namespace and the value is the
   * namespace which the actual cache is bound to.
   */
  protected final Map cacheRefMap = new HashMap();
  下面是一些get set方法 
  省略

MyBatis初始化的过程,就是创建 Configuration对象的过程。

怎么初始化?

MyBatis的初始化方式可以有两种方式:

  • 基于XML配置文件:基于XML配置文件的方式是将MyBatis的所有配置信息放在XML文件中,MyBatis通过加载并XML配置文件,将配置文信息组装成内部的Configuration对象
  • 基于Java API:这种方式不使用XML配置文件,需要MyBatis使用者在Java代码中,手动创建Configuration对象,然后将配置参数set 进入Configuration对象中

下面以基于XML配置文件进行初始化的方式来具体分析MyBatis是如何进行初始化的。
这里以MyBatis的独立配置文件为例,不是和Spring整合的配置文件。

InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

除了可以使用InputStream读取文件流之外, 还可以使用Reader
下面的代码是Mybatis源码中关于SqlSession的测试例子

public class SqlSessionTest extends BaseDataTest {

  private static SqlSessionFactory sqlMapper;

  @BeforeClass
  public static void setup() throws Exception {
    createBlogDataSource();
    final String resource = "org/apache/ibatis/builder/MapperConfig.xml";
    final Reader reader = Resources.getResourceAsReader(resource);
    sqlMapper = new SqlSessionFactoryBuilder().build(reader);
  }
    ...
    ...
    ...
}

SqlSessionFactoryBuilder根据传入的数据流生成Configuration对象,然后根据Configuration对象创建默认的SqlSessionFactory实例。

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      // parser.parse() 返回Configuration
      // build(configuration) 返回DefaultSqlSessionFactory
      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) {
    // 默认是DefaultSqlSessionFactory
    return new DefaultSqlSessionFactory(config);
  }
public Configuration parse() {
    // 为什么Each XMLConfigBuilder can only be used once????
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    //会从XPathParser中取出 节点对应的XNode对象,然后解析它的子节点
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      // parser.parse() 返回Configuration
      // build(configuration) 返回DefaultSqlSessionFactory
      return build(parser.parse());

从以上代码也可知MyBatis默认初始化的SessionFactory是DefaultSqlSessionFactory。
(SessionFactory接口有两个实现类 ,一个是SqlSessionManager,一个是DefaultSqlSessionFactory。)

对于初始化工程中涉及到的几个类,我们再具体分析一下

SqlSessionFactoryBuilder : SqlSessionFactory的构造器,用于创建SqlSessionFactory,采用了Builder设计模式
Configuration :该对象是mybatis-config.xml文件中所有mybatis配置信息的容器
SqlSessionFactory:SqlSession工厂类,以工厂形式创建SqlSession对象,采用了Factory工厂设计模式
XmlConfigBuilder :负责将mybatis-config.xml配置文件解析成Configuration对象,供SqlSessonFactoryBuilder使用,创建SqlSessionFactory

parse()方法是如何处理XML文件,生成Configuration对象的呢?

1、XMLConfigBuilder会将XML配置文件的信息转换为Document对象,而XML配置定义文件DTD转换成XMLMapperEntityResolver对象,然后将二者封装到XpathParser对象中,XpathParser的作用是提供根据Xpath表达式获取基本的DOM节点Node信息的操作。
MyBatis源码解析 - MyBatis初始化_第1张图片

2、之后XMLConfigBuilder调用parse()方法:会从XPathParser中取出 节点对应的Node对象,然后解析此Node节点的子Node:properties, settings, typeAliases,typeHandlers, objectFactory, objectWrapperFactory, plugins, environments,databaseIdProvider, mappers
Xml文件元素和Configuration属性映射表:

properties :Properties variables。
settings:Integer defaultStatementTimeout、Integer defaultFetchSize、ExecutorType defaultExecutorType……
typeAliases:TypeAliasRegistry typeAliasRegistry。
typeHandlers:TypeHandlerRegistry typeHandlerRegistry。
environments:Environment environment。配置多个元素时,Mybatis只会读取默认的那一个
mappers:MapperRegistry mapperRegistry
等等 具体的可以看下面的parseConfiguration方法的代码,解析哪些内容

我们具体看下parse()方法,看它如何根据XML文件来生成Configuration对象的

private void parseConfiguration(XNode root) {
    try {
      propertiesElement(root.evalNode("properties")); //issue #117 read properties first
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      settingsElement(root.evalNode("settings"));
      environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

在对mappers元素进行解析的时候,用到的是mapperElement(root.evalNode(“mappers”));
关于对于mappers元素的解析后面的文章进行分享。

3、 然后将这些值解析出来设置到Configuration对象中。
4、返回Configuration对象

参考:https://blog.csdn.net/luanlouis/article/details/37744073

你可能感兴趣的:(MyBatis)