MyBatis源码解读-SqlSessionFactory

0.从配置文件开始

要了解MyBatis的的源码,咱们能够看看咱们平时在Spring容器中使用MyBatis的配置文件,找到最基本的入口.java

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">    
   <property name="dataSource" ref="dataSource" />  
   <property name="configLocation" value="classpath:configuration.xml"></property>   
   <property name="mapperLocations" value="classpath:com/sage/mybatis/mapper/*.xml"/>    
   <property name="typeAliasesPackage" value="com.sage.entity" />    
</bean>

Spring会调用SqlSessionFactoryBean这个工厂bean的无参构造函数,同时注入dataSource,Mapper文件的路径,进行sqlSessionFactory的初始化.这里面的SqlSessionFactoryBean,使用的是mybatis-spring包.spring

1.建立SqlSessionFactory

咱们来看一下,MyBatis是如何经过XML配置来建立SqlSessionFactory.sql

protected SqlSessionFactory buildSqlSessionFactory() throws IOException {

    Configuration configuration;

    XMLConfigBuilder xmlConfigBuilder = null;
    if (this.configuration != null) {
      configuration = this.configuration;
      if (configuration.getVariables() == null) {
        configuration.setVariables(this.configurationProperties);
      } else if (this.configurationProperties != null) {
        configuration.getVariables().putAll(this.configurationProperties);
      }
    } else if (this.configLocation != null) {
        // 若是传入了MyBatis Config文件的路径,初始化xmlConfigBuilder 并得到里面的配置信息
      xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
      configuration = xmlConfigBuilder.getConfiguration();
    } else {
      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("Property `configuration` or 'configLocation' not specified, using default MyBatis Configuration");
      }

      configuration = new Configuration();
      configuration.setVariables(this.configurationProperties);
    }

    if (this.objectFactory != null) {
      configuration.setObjectFactory(this.objectFactory);
    }

    if (this.objectWrapperFactory != null) {
      configuration.setObjectWrapperFactory(this.objectWrapperFactory);
    }

    if (this.vfs != null) {
      configuration.setVfsImpl(this.vfs);
    }

    // 若是在Spring的配置文件中,配置类实体类包的别名typeAliasesPackage
    if (hasLength(this.typeAliasesPackage)) {
      String[] typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage,
          ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
      for (String packageToScan : typeAliasPackageArray) {
          // 不使用MyBatis Config文件里的实体类包别名配置
        configuration.getTypeAliasRegistry().registerAliases(packageToScan,
                typeAliasesSuperType == null ? Object.class : typeAliasesSuperType);
        if (LOGGER.isDebugEnabled()) {
          LOGGER.debug("Scanned package: '" + packageToScan + "' for aliases");
        }
      }
    }

    if (!isEmpty(this.typeAliases)) {
      for (Class<?> typeAlias : this.typeAliases) {
        configuration.getTypeAliasRegistry().registerAlias(typeAlias);
        if (LOGGER.isDebugEnabled()) {
          LOGGER.debug("Registered type alias: '" + typeAlias + "'");
        }
      }
    }

    //若是配置类插件,注册插件,从这咱们能够看到,插件类是实现Interceptor, 配置文件里能够传入数组
    if (!isEmpty(this.plugins)) {
      for (Interceptor plugin : this.plugins) {
        configuration.addInterceptor(plugin);
        if (LOGGER.isDebugEnabled()) {
          LOGGER.debug("Registered plugin: '" + plugin + "'");
        }
      }
    }

    if (hasLength(this.typeHandlersPackage)) {
      String[] typeHandlersPackageArray = tokenizeToStringArray(this.typeHandlersPackage,
          ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
      for (String packageToScan : typeHandlersPackageArray) {
        configuration.getTypeHandlerRegistry().register(packageToScan);
        if (LOGGER.isDebugEnabled()) {
          LOGGER.debug("Scanned package: '" + packageToScan + "' for type handlers");
        }
      }
    }

    if (!isEmpty(this.typeHandlers)) {
      for (TypeHandler<?> typeHandler : this.typeHandlers) {
        configuration.getTypeHandlerRegistry().register(typeHandler);
        if (LOGGER.isDebugEnabled()) {
          LOGGER.debug("Registered type handler: '" + typeHandler + "'");
        }
      }
    }

    //databaseIdProvider 多数据库支持 在编写Mapper的时候 指定databaseId
    //用于多数据源的状况,我会放到以后的文章来说解如何使用
    if (this.databaseIdProvider != null) {//fix #64 set databaseId before parse mapper xmls
      try {
        configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
      } catch (SQLException e) {
        throw new NestedIOException("Failed getting a databaseId", e);
      }
    }

    //缓存配置
    if (this.cache != null) {
      configuration.addCache(this.cache);
    }

    //若是xmlConfigBuilder存在则开始分析建立Configuration对象  
    if (xmlConfigBuilder != null) {
      try {
        xmlConfigBuilder.parse();

        if (LOGGER.isDebugEnabled()) {
          LOGGER.debug("Parsed configuration file: '" + this.configLocation + "'");
        }
      } catch (Exception ex) {
        throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
      } finally {
        ErrorContext.instance().reset();
      }
    }

    //事务工厂配置
    if (this.transactionFactory == null) {
      this.transactionFactory = new SpringManagedTransactionFactory();
    }

    //设置configuration的环境变量信息
    configuration.setEnvironment(new Environment(this.environment, this.transactionFactory, this.dataSource));

    //若是指定了mapper文件的路径
    if (!isEmpty(this.mapperLocations)) {
      for (Resource mapperLocation : this.mapperLocations) {
        if (mapperLocation == null) {
          continue;
        }

        try {
            //将xml的mapper文件进行解析转换
          XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
              configuration, mapperLocation.toString(), configuration.getSqlFragments());
          xmlMapperBuilder.parse();
        } catch (Exception e) {
          throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
        } finally {
          ErrorContext.instance().reset();
        }

        if (LOGGER.isDebugEnabled()) {
          LOGGER.debug("Parsed mapper file: '" + mapperLocation + "'");
        }
      }
    } else {
      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("Property 'mapperLocations' was not specified or no matching resources found");
      }
    }

    //建立SqlSessionFactory
    return this.sqlSessionFactoryBuilder.build(configuration);
  }

从上面的代码咱们能够简单的看出,在初始化SqlSessionFactory的时候,会经过工厂Bean对象,并传入配置参数进行建立的.咱们能够看到,MyBatis自己并不提供事务的支持,使用的是Spring的事务.同时也和大部分框架,将XML解析为配置对象,方便使用.数据库

相关文章
相关标签/搜索