`
blue2048
  • 浏览: 178239 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Mybatis深入剖析 - 配置框架初始化分析

阅读更多

原始的初始化流程

1.    配置Configuration xml文件

2.  SqlSessionFactoryBuilder.build拿到SqlSessionFactory(全局唯一)

3.  代码中的调用如下

       SqlSession session= sqlSessionFactory.openSession();

       UserDao userDao = session.getMapper(UserDao.class);

       UserVo vo = new UserVo();

       vo.setName("a")

       List<UserVo> users = userDao.queryUsers(user);

 

结合spring的初始化流程分析

以spring配置为例,对SqlSessionFactoryBean和SqlSessionTemplate进行分析

 

<bean id="bssSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="classpath:mybatis-config.xml" />
        <property name="mapperLocations" value="classpath:/mapper/**/*Mapper.xml"></property>
        <property name="dataSource" ref="bssDataSource" />
 </bean>

 
 

进入SqlSessionFactoryBean类,其核心的初始化方法

 

在此方法初始化Mybatis核心类,Configuration,初始化的顺序如下

 

    a) 根据configLocation初始化配置信息

 

xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
            configuration = xmlConfigBuilder.getConfiguration();

 
      b) 根据typeAliasesPackage加载类别名(typeAliasesPackage:它一般对应我们的实体类所在的包,这个时候会自动取对应包中不包括包名的简单类名作为包括包名的别名。多个package之间可以用逗号或者分号等来进行分隔。

      c) 根据typeAliases接在xml配置的别名

      d) 根据typeHandlersPackage和typeHandlers加载自定义的类型转化类

      e) 根据传入的TransactionFactory构造configuration的Environment,如果为设置此项,默认使用spring的SpringManagedTransactionFactory

      f) 根据mapperLocations,调用XMLMapperBuilder解析mapper文件,Mapper文件中的片段解析成MappedStatement对象,以Id为key存储在Configuration的map中

      g) SqlSessionFactoryBuilder根据初始化好的configuration,构造SqlSessionFactory


              

public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

 
 SqlSessionTemplate是spring封装mybatis的另一个重要类,这个类是所有数据库操作的接口门面

 

 <bean id="bssSqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="bssSqlSessionFactory" />
    </bean>

 
 a)       根据构造函数的sqlSessionFactory,executorType,exceptionTranslator初始化,其中executorType有以下三种,分别对应了不同的sql执行策略

 

public enum ExecutorType {
  SIMPLE, REUSE, BATCH
}

 

 b)       这里可能比较重要的是sqlSession的代理对象,看拦截器的代码可以知道,此代理的作用是在非事务的session操作进行提交;异常处理;session close

 

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

 
 

    private class SqlSessionInterceptor implements InvocationHandler {
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            final SqlSession sqlSession = SqlSessionUtils.getSqlSession(
                    SqlSessionTemplate.this.sqlSessionFactory,
                    SqlSessionTemplate.this.executorType,
                    SqlSessionTemplate.this.exceptionTranslator);
            try {
                Object result = method.invoke(sqlSession, args);
                if (!SqlSessionUtils.isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
                    sqlSession.commit();
                }
                return result;
            } catch (Throwable t) {
                Throwable unwrapped = ExceptionUtil.unwrapThrowable(t);
                if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
                    Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
                    if (translated != null) {
                        unwrapped = translated;
                    }
                }
                throw unwrapped;
            } finally {
                SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
            }
        }
    }

 
 

 

 附buildSqlSessionFactory源码

 

 protected SqlSessionFactory buildSqlSessionFactory() throws IOException {

        Configuration configuration;
        
        XMLConfigBuilder xmlConfigBuilder = null;
        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();
            configuration.setVariables(this.configurationProperties);
        }
                
        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");
                }
            }
        }

        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 + "'");
                }
            }
        }

        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 + "'");
                }
            }
        }

        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();
            }
        }

        if (this.transactionFactory == null) {
            this.transactionFactory = new SpringManagedTransactionFactory(this.dataSource);
        }

        Environment environment = new Environment(this.environment, this.transactionFactory, this.dataSource);
        configuration.setEnvironment(environment);
        
        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);
    }

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics