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解析爲配置對象,方便使用.數據庫

相關文章
相關標籤/搜索