第四篇 mybatis的运行原理(1):重要组件的介绍

一、组件介绍

相比其他框架,mybatis的组件构成还是相对简单的,下面是网络上比较常见的一张图,关于mybatis的执行流程,其中是mybatis的最常用的组件:


  在来学习mybatis的源码和底层原理之前,先来了解各大组件的作用和生命周期:
    (1)SqlSessionFactoryBuilder
                  SqlSessionFactoryBuilder是利用XML或者Java编码获得资源来构建SqlSessionFactory的,通过它可以构建多个SqlsessionFactory,它的作用就是一个构建器,一旦创建SqlSessionFactory,
           它的作用就会消失,所以构建SqlsessionFactory成功后会废弃回收。所以的它的生命周期只存在于方法的局部,它的作用就是生成SqlSessionFactory对象。

   (2)SqlSessionFactory对象
                SqlSessionFactory的作用就是创建SqlSession,Sqlsession相当于JDBC中的Connection对象,每次访问数据库都需要创建SqlSession,前面的文章就已经说过,一个SqlSessionFactory对应一个数据库,
           那么能不能多个对应一个数据库了?是可以的,但是这样做的话,有多个SqlSessionFactory就会有很多的数据库连接,这样会导致数据库连接资源容易耗尽,且不易管理数据库连接,所以,mybatis的设计采用的单例
           模式,这样可以更有效的管理数据库的资源分配。由于SqlSessionFactory一直维护着SqlSession的创建,所以SqlSessionFactory的生命周期是框架运行的整个过程。

   (3)SqlSession
               SqlSession对象时连接数据库的通道,更准确地说是访问数据库的一次会话,当发起访问数据库的请求时,创建一个SqlSession对象,请求完成关闭SqlSession。  要注意的是,SqlSession是一个线程不安全的对象,
         在涉及多线程的时候,要保证操作数据库的隔离级别 、数据库锁等高级特性,此外,SqlSession使用完成后都必须及时的关闭,避免占用连接资源,导致数据库宕机

(4)Mapper
               Mapper是一个接口,它的作用是发送SQL,当然,作为接口,当然不能执行SQL, 所以Mapper是代理方式完成这一操作, 然后返回我们需要的结果,或者执行SQL从而修改数据库的数据,具体实现,后面会说。
        因此,Mapper是一个方法级别的东西,当SqlSession销毁时,Mapper也会随之销毁。

二、SqlSessionFactory的创建

       前面已经知道了mybatis的使用,执行流程以及重要的组件构成,但是对于一名开发者来说,知道这些远远不够,学习mybatis的底层原理,可以帮我们更好解决框架使用中的问题,甚至可以修改框架或者自定义插件来满足我们的业务需求。
 所以我们从源码层面一步一步走mybatis的执行流程。 首先,从mybatis加载解析mybatis的配置文件mybatisConfig.xml开始。我们先来看看我们是如何创建SqlSessionFactory的:

  /*资源*/
   InputStream is = UserService.class.getClassLoader().getResourceAsStream("mybatis/mybatisConfig.xml")
   /*创建SqlSessionFactory*/
   SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

由上述代码可以看出SqlSessionFactory的创建是依托于SqlSessionFactoryBuilder类的build方法,打开该类SqlSessionFactoryBuilder由众多形式的build方法组成,尽管方法有很多,但是目的只有一个那就是

解析资源,创建SqlSessionFactory,所以我们以public SqlSessionFactory build(InputStream inputStream)为例深入

   public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
        try {
          /*解析xml文件,封装成一个XMLConfigBuilder对象*/
          XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
          /*生成一个参数类Configuration对象,然后通过该参数类创建DefaultSqlSessionFactory对象*/
          Configuration config = parser.parse();
          return build(config);
        } 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);
      }

    }

java对于xml文件资源的解析有dom解析,sax解析,dom4j解析,mybatis使用的dom方式,具体xml会在别的文章中说到,xml解析会得到一个  XMLConfigBuilder对象,

之后,XMLConfigBuilder对象会通过parse方法初始为一个Configuration对象,看看Configuration对象的内部,

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 <? extends Log> logImpl;
  protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
  protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
  protected Set<String> lazyLoadTriggerMethods = new HashSet<String>(Arrays.asList(new String[] { "equals", "clone", "hashCode", "toString" }));
  protected Integer defaultStatementTimeout;
  protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
  protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;
.....
.....

从熟悉的变量名就可以联想到这个对象就是xml文件里对mybatis配置属性,那为什么这些属性不直接放到DefaultSqlSessionFactory类里面去了,这主要是由于创建SqlSessionFactory

需要的参数复杂,如果直接放到类的构造方法里面,这会导致大量的逻辑存在于类的构造方法中,所以使用一个参数类总领全局,分步构建,可以有效降低这种逻辑混乱的问题。

所以Configuration 对象也SqlSessionFactory创建过程中最重要的一个类。甚至mybatis的大多数的配置都是源于Configuration

Configuration 对象的作用:

    1. 读取配置文件,包括初始化xml和映射器xml

    2. 初始化基础配置,如果xml文件里set和typehandle

    3. 提供单例,生成单例,为之后生成session提供配置

    4. 执行一些重要的对象方法,如构建构造器executor等。
SqlSessionFactory接口有两个实现类:DefaultSqlSessionFactory类和SqlSessionManager类,但是是使用DefaultSqlSessionFactory创建SqlSessionFactory对象,下一篇将会剖析DefaultSqlSessionFactory具体的创建过程


原文地址:https://www.cnblogs.com/zhexuejun/p/11233041.html