mybatis 初始化解析

一,SqlSessionFactory 初始化

在基本的 MyBatis 中,sessionFactory可以使用 SqlSessionFactoryBuilder 来创建。而在 MyBatis-spring 中,则使用 SqlSessionFactoryBean 来替代,在SqlSessionFactoryBean 其实还是调用了sqlSessionFactoryBuilder.build(configuration)来创建sessionFactory。

相当于spring的SqlSessionFactoryBean 做了一层封装,通过实现spring的接口这读取配置,填充configuration,然后再创建sessionFactory。

定义SqlSessionFactoryBean:

<bean id="session_cmail_mail_web" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="ds_cmail_web"/>
		<property name="configLocation">
			<value>classpath:xml/sqlmap/mysql-mail-base-map-config.xml</value>
		</property>
	</bean>

查看SqlSessionFactoryBean

public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {

实现了FactoryBean和InitializingBean,所以在bean初始化时,会执行afterPropertiesSet(),查看代码:

/**
     * {@inheritDoc}
     */
    public void afterPropertiesSet() throws Exception {
        Assert.notNull(dataSource, "Property 'dataSource' is required");
        Assert.notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");

        this.sqlSessionFactory = buildSqlSessionFactory();
    }

在buildSqlSessionFactory() 这个方法中,读取,创建sessionFactory .

截取主要方法:

    //读取<configuration> 配置
    if (this.configLocation != null) {
            xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(),     
                 null, this.configurationProperties);
            configuration = xmlConfigBuilder.getConfiguration();
        } else {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Property 'configLocation' not specified, using default 
                  MyBatis Configuration");
            }
            configuration = new Configuration();
        }
      //如果SqlSessionFactoryBean的property有配置typeAliasesPackage,则写入configuration          
      if (StringUtils.hasLength(this.typeAliasesPackage)) {
            String[] typeAliasPackageArray = 
               StringUtils.tokenizeToStringArray(this.typeAliasesPackage, 
                ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
            for (String packageToScan : typeAliasPackageArray) {
                configuration.getTypeAliasRegistry().registerAliases(packageToScan);    
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Scanned package: '" + packageToScan + "' for 
                  aliases");
                }
            }
        }
        //如果SqlSessionFactoryBean的property有配置typeAliases,则写入configuration
        if (!ObjectUtils.isEmpty(this.typeAliases)) {
            for (Class<?> typeAlias : this.typeAliases) {
                configuration.getTypeAliasRegistry().registerAlias(typeAlias);
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Registered type alias: '" + typeAlias + "'");
                }
            }
        }
        //如果SqlSessionFactoryBean的property有配置plugins,则写入configuration
        if (!ObjectUtils.isEmpty(this.plugins)) {
            for (Interceptor plugin : this.plugins) {
                configuration.addInterceptor(plugin);
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Registered plugin: '" + plugin + "'");
                }
            }
        }

        if (StringUtils.hasLength(this.typeHandlersPackage)) {
            String[] typeHandlersPackageArray = StringUtils.tokenizeToStringArray(this.typeHandlersPackage, 
                ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
            for (String packageToScan : typeHandlersPackageArray ) {
                configuration.getTypeHandlerRegistry().register(packageToScan);    
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Scanned package: '" + packageToScan + "' for type handlers");
                }
            }
        }
        
        if (!ObjectUtils.isEmpty(this.typeHandlers)) {
            for (TypeHandler typeHandler : this.typeHandlers) {
                configuration.getTypeHandlerRegistry().register(typeHandler);
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Registered type handler: '" + typeHandler + "'");
                }
            }
        }
      //在这个方法中,会读取<configuration> 中的所有配置包括typeAliases,plugins,mappers...
        if (xmlConfigBuilder != null) {
            try {
                xmlConfigBuilder.parse();
                
                if (this.logger.isDebugEnabled()) {
                    this.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();
            }
        }
        //使用spring事务管理
        if (this.transactionFactory == null) {
            this.transactionFactory = new 
             SpringManagedTransactionFactory(this.dataSource);
        }

        Environment environment = new Environment(this.environment,                 
         this.transactionFactory, this.dataSource);
        configuration.setEnvironment(environment);
        //如果有sqlSessionFactoryBean有配置mappers,则读取
        if (!ObjectUtils.isEmpty(this.mapperLocations)) {
            for (Resource mapperLocation : this.mapperLocations) {
                if (mapperLocation == null) {
                    continue;
                }

                // this block is a workaround for issue             
                 http://code.google.com/p/mybatis/issues/detail?id=235
                // when running MyBatis 3.0.4. But not always works. 
                // Not needed in 3.0.5 and above.
                String path;
                if (mapperLocation instanceof ClassPathResource) {
                    path = ((ClassPathResource) mapperLocation).getPath();
                } else {
                    path = mapperLocation.toString();
                }

                try {
                    XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
                            configuration, path, configuration.getSqlFragments());
                    xmlMapperBuilder.parse();
                } catch (Exception e) {
                    throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
                } finally {
                    ErrorContext.instance().reset();
                }

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

        return this.sqlSessionFactoryBuilder.build(configuration);

二.MapperFactoryBean的作用

定义MapperFactoryBean,主要是生成sqlSession以及把Mapper接口添加到Configuration对象中。MapperFactoryBean实现了FactoryBean接口,所以会使用getObject(),

 public T getObject() throws Exception {
        return getSqlSession().getMapper(this.mapperInterface);
    }

2.1生成sqlSession时使用动态代理:

this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
                SqlSessionFactory.class.getClassLoader(),
                new Class[] { SqlSession.class }, 
                new SqlSessionInterceptor());

2.2 把Mapper接口添加到Configuration对象

@Override
    protected void checkDaoConfig() {
        super.checkDaoConfig();
        
        Assert.notNull(this.mapperInterface, "Property 'mapperInterface' is required");

        Configuration configuration = getSqlSession().getConfiguration();
        if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
            try {
                configuration.addMapper(this.mapperInterface);
            } catch (Throwable t) {
                logger.error("Error while adding the mapper '" + this.mapperInterface + "'             
                 to configuration.", t);
                throw new IllegalArgumentException(t);
            } finally {
                ErrorContext.instance().reset();
            }
        }
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值