Mybatis整体架构与初始化

发布时间 2023-07-04 21:42:29作者: ayiZzzz

Mybatis整体架构

MyBatis的整体架构分为三层,分别是基础支持层、核心处理层和接口层

  • SqlSession

1、SqlSession是Mybatis最重要的构建之一,可以简单的认为Mybatis一系列的配置目的是生成类似 JDBC生成的Connection对象的SqlSession对象,这样才能与数据库开启“沟通”,通过SqlSession可以实现增删改查
2、SqlSession 是门面设计模式的经典运用,SqlSession实现增删改查,全靠Executor 来进行执行
3、SqlSession 是一个线程不安全的类,在多线程情况下应保证每一个线程使用不同的 SqlSession
4、SqlSession 是 Connection 对应的高级封装


Mybatis 初始化流程

        // 资源路径 resource/mybatis-config.xml
        String resource = "mybatis-config.xml";
        // 包装成 InputStream 
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 通过构建者模式创建 SqlSessionFactory 
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  • 初始化 SqlSessionFactory 时序图
  1. 调用SqlSessionFactoryBuilder对象的build(inputStream)方法;
  2. SqlSessionFactoryBuilder会根据输入流inputStream等信息创建XMLConfigBuilder对象;
  3. SqlSessionFactoryBuilder调用XMLConfigBuilder对象的parse()方法;
  4. XMLConfigBuilder对象返回Configuration对象;
  5. SqlSessionFactoryBuilder根据Configuration对象创建一个DefaultSessionFactory对象;
  6. SqlSessionFactoryBuilder返回 DefaultSessionFactory对象给Client,供Client使用。

  • 初始化涉及到的几个对象
    1、SqlSessionFactoryBuilder : SqlSessionFactory的构造器,用于创建SqlSessionFactory,采用了Builder设计模式
    2、Configuration :该对象是mybatis-config.xml文件中所有mybatis配置信息
    3、SqlSessionFactory:SqlSession工厂类,以工厂形式创建SqlSession对象,采用了Factory工厂设计模式
    4、XmlConfigParser :负责将mybatis-config.xml配置文件解析成Configuration对象,共SqlSessonFactoryBuilder使用,创建SqlSessionFactory

解析 XML

1、Document:将 XML 数据在内存中解析成一个树,通过对树的操作来操作XML。
2、SAX:SAX不用将整个文档加载到内存,基于事件驱动的API(Observer模式),他按照xml文件的顺序一步一步的来解析
3、XPath:MyBatis使用XPath技术解析XML文档,MyBatis提供的XPathParser类对XPath的进行了封装,提供了更为友好的方法以方便用户使用。


XPathParser

public class XPathParser {

    /**
     * Document对象
     */
  private final Document document;
  /**
    设置是否启用DTD验证
  */
  private boolean validation;
  /**
     * 用于加载本地的DTD文件
     */
  private EntityResolver entityResolver;
  private Properties variables;
   // 用来解析XML文档的XPath对象  
  private XPath xpath;
}

1、XMLConfigBuilder 会将 mybatis-config.xml 以及对应的 Mapper 配置文件转换成 Document 对象
2、将 mybatis-config.xml 配置定义文件 dtd 转换为 EntityResolver


  • 代码 XMLConfigBuilder
  public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }

private void parseConfiguration(XNode root) {
    try {
      //1.首先处理properties 节点	
      propertiesElement(root.evalNode("properties")); //issue #117 read properties first
      //2.处理typeAliases
      typeAliasesElement(root.evalNode("typeAliases"));
      //3.处理插件
      pluginElement(root.evalNode("plugins"));
      //4.处理objectFactory
      objectFactoryElement(root.evalNode("objectFactory"));
      //5.objectWrapperFactory
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      //6.settings
      settingsElement(root.evalNode("settings"));
      //7.处理environments
      environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631
      //8.database
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      //9. typeHandlers
      typeHandlerElement(root.evalNode("typeHandlers"));
      //10 mappers
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

注意:1、之后XMLConfigBuilder调用parse()方法:会从XPathParser中取出 节点对应的Node对象,然后解析此Node节点的子Node:properties, settings, typeAliases,typeHandlers, objectFactory, objectWrapperFactory, plugins, environments,databaseIdProvider, mappers
2、注意解析顺序需要与 mybatis-config.xml 的配置顺序相同
3、第 10 部会解析 mappers 节点,并根据对应的 url , packing , resource 等方式绑定对应的 *Mapper.xml,并配置到 Configuration 中


设置 Configuration

/*
   解析environments节点,并将结果设置到Configuration对象中
   注意:创建envronment时,如果SqlSessionFactoryBuilder指定了特定的环境(即数据源);
         则返回指定环境(数据源)的Environment对象,否则返回默认的Environment对象;
         这种方式实现了MyBatis可以连接多数据源
*/
private void environmentsElement(XNode context) throws Exception
{
    if (context != null)
    {
        if (environment == null)
        {
            environment = context.getStringAttribute("default");
        }
        for (XNode child : context.getChildren())
        {
            String id = child.getStringAttribute("id");
            if (isSpecifiedEnvironment(id))
            {
                //1.创建事务工厂 TransactionFactory
                TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
                DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
                //2.创建数据源DataSource
                DataSource dataSource = dsFactory.getDataSource();
                //3. 构造Environment对象
                Environment.Builder environmentBuilder = new Environment.Builder(id)
                .transactionFactory(txFactory)
                .dataSource(dataSource);
                //4. 将创建的Envronment对象设置到configuration 对象中
                configuration.setEnvironment(environmentBuilder.build());
            }
        }
    }
}
private boolean isSpecifiedEnvironment(String id)
{
    if (environment == null)
    {
        throw new BuilderException("No environment specified.");
    }
    else if (id == null)
    {
        throw new BuilderException("Environment requires an id attribute.");
    }
    else if (environment.equals(id))
    {
        return true;
    }
    return false;
}

返回 Configuration 对象