分享

Mybatis3源码分析(一):从sqlSession说起

 WindySky 2018-03-01
                              

分析MyBatis3的源码首先得从sqlSessionFactory开始,先来看一段spring配置文件中Mybaits的sqlSessionFactory的配置。

  1. <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"  destroy-method="close">    
  2.    <property name="driverClassName" value="${jdbc.driver}" />    
  3.    <property name="url" value="${jdbc.url}" />    
  4.    <property name="username" value="${jdbc.username}" />    
  5.    <property name="password" value="${jdbc.password}" />    
  6. </bean>    
  7. <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">    
  8.    <property name="dataSource" ref="dataSource" />  
  9.    <property name="configLocation" value="classpath:configuration.xml"></property>   
  10.    <property name="mapperLocations" value="classpath:com/tiantian/mybatis/mapper/*.xml"/>    
  11.    <property name="typeAliasesPackage" value="com.tiantian.mybatis.model" />    
  12. </bean>  
  13. <bean id="blogMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">    
  14.        <property name="mapperInterface"    
  15.            value="com.tiantian.mybatis.mapper.BlogMapper" />    
  16.       <property name="sqlSessionFactory" ref="sqlSessionFactory" />    
  17. </bean>     

    spring会调用sqlSessionFactory的无参构造函数创建实例,并将dataSource和映射文件路径注入进去初始化sqlSessionFactory。这里的SqlSessionFactoryBean的实现依赖于mybatis社区自行开发的支持包,我们来看看它是怎么读取xml配置文件创建sessionFactory的:

  1. protected SqlSessionFactory buildSqlSessionFactory() throws IOException {  
  2.     //代表配置的对象  
  3.     Configuration configuration;  
  4.     //xml配置创建者  
  5.     XMLConfigBuilder xmlConfigBuilder = null;  
  6.     //spring中注入的配置文件路径,如果不存在使用默认配置  
  7.     if (this.configLocation != null) {  
  8.       xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);  
  9.       configuration = xmlConfigBuilder.getConfiguration();  
  10.     } else {  
  11.       if (logger.isDebugEnabled()) {  
  12.         logger.debug("Property 'configLocation' not specified, using default MyBatis Configuration");  
  13.       }  
  14.       configuration = new Configuration();  
  15.       configuration.setVariables(this.configurationProperties);  
  16.     }  
  17.     //如果配置了objectFactory使用此配置类  
  18.     if (this.objectFactory != null) {  
  19.       configuration.setObjectFactory(this.objectFactory);  
  20.     }  
  21.     //同上  
  22.     if (this.objectWrapperFactory != null) {  
  23.       configuration.setObjectWrapperFactory(this.objectWrapperFactory);  
  24.     }  
  25.     //如果配置了typeAliases(实体类别名标签)的基包则不用在configuration文件中配置  
  26.     if (hasLength(this.typeAliasesPackage)) {  
  27.       String[] typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage,  
  28.           ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);  
  29.       for (String packageToScan : typeAliasPackageArray) {  
  30.         configuration.getTypeAliasRegistry().registerAliases(packageToScan,  
  31.                 typeAliasesSuperType == null ? Object.class : typeAliasesSuperType);  
  32.         if (logger.isDebugEnabled()) {  
  33.           logger.debug("Scanned package: '" + packageToScan + "' for aliases");  
  34.         }  
  35.       }  
  36.     }  
  37.     //如果是直接配置的实体类别名则在配置对象中注册  
  38.     if (!isEmpty(this.typeAliases)) {  
  39.       for (Class<?> typeAlias : this.typeAliases) {  
  40.         configuration.getTypeAliasRegistry().registerAlias(typeAlias);  
  41.         if (logger.isDebugEnabled()) {  
  42.           logger.debug("Registered type alias: '" + typeAlias + "'");  
  43.         }  
  44.       }  
  45.     }  
  46.     //是否配置mybaits的一些插件  
  47.     if (!isEmpty(this.plugins)) {  
  48.       for (Interceptor plugin : this.plugins) {  
  49.         configuration.addInterceptor(plugin);  
  50.         if (logger.isDebugEnabled()) {  
  51.           logger.debug("Registered plugin: '" + plugin + "'");  
  52.         }  
  53.       }  
  54.     }  
  55.     //是否配置typeHandler的基包  
  56.     if (hasLength(this.typeHandlersPackage)) {  
  57.       String[] typeHandlersPackageArray = tokenizeToStringArray(this.typeHandlersPackage,  
  58.           ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);  
  59.       for (String packageToScan : typeHandlersPackageArray) {  
  60.         configuration.getTypeHandlerRegistry().register(packageToScan);  
  61.         if (logger.isDebugEnabled()) {  
  62.           logger.debug("Scanned package: '" + packageToScan + "' for type handlers");  
  63.         }  
  64.       }  
  65.     }  
  66.     //是否直接配置了typeHandler  
  67.     if (!isEmpty(this.typeHandlers)) {  
  68.       for (TypeHandler<?> typeHandler : this.typeHandlers) {  
  69.         configuration.getTypeHandlerRegistry().register(typeHandler);  
  70.         if (logger.isDebugEnabled()) {  
  71.           logger.debug("Registered type handler: '" + typeHandler + "'");  
  72.         }  
  73.       }  
  74.     }  
  75.     //如果xmlConfigBuilder存在则开始分析创建Configuration对象  
  76.     if (xmlConfigBuilder != null) {  
  77.       try {  
  78.         xmlConfigBuilder.parse();  
  79.   
  80.         if (logger.isDebugEnabled()) {  
  81.           logger.debug("Parsed configuration file: '" + this.configLocation + "'");  
  82.         }  
  83.       } catch (Exception ex) {  
  84.         throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);  
  85.       } finally {  
  86.         ErrorContext.instance().reset();  
  87.       }  
  88.     }  
  89.     //事务工厂是否配置  
  90.     if (this.transactionFactory == null) {  
  91.       this.transactionFactory = new SpringManagedTransactionFactory();  
  92.     }  
  93.     //设置Configuration的环境对象  
  94.     Environment environment = new Environment(this.environment, this.transactionFactory, this.dataSource);  
  95.     configuration.setEnvironment(environment);  
  96.    
  97.     if (this.databaseIdProvider != null) {  
  98.       try {  
  99.         configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));  
  100.       } catch (SQLException e) {  
  101.         throw new NestedIOException("Failed getting a databaseId", e);  
  102.       }  
  103.     }  
  104.     //是否配置mapperLocations,如果存在解析创建这些mapper,mapper是mybaits管理各种sql的容器  
  105.     if (!isEmpty(this.mapperLocations)) {  
  106.       for (Resource mapperLocation : this.mapperLocations) {  
  107.         if (mapperLocation == null) {  
  108.           continue;  
  109.         }  
  110.   
  111.         try {  
  112.           XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),  
  113.               configuration, mapperLocation.toString(), configuration.getSqlFragments());  
  114.           xmlMapperBuilder.parse();  
  115.         } catch (Exception e) {  
  116.           throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);  
  117.         } finally {  
  118.           ErrorContext.instance().reset();  
  119.         }  
  120.   
  121.         if (logger.isDebugEnabled()) {  
  122.           logger.debug("Parsed mapper file: '" + mapperLocation + "'");  
  123.         }  
  124.       }  
  125.     } else {  
  126.       if (logger.isDebugEnabled()) {  
  127.         logger.debug("Property 'mapperLocations' was not specified or no matching resources found");  
  128.       }  
  129.     }  
  130.     //创建sqlSessionFactoryBean  
  131.     return this.sqlSessionFactoryBuilder.build(configuration);  
  132.   }  

    从mybatis创建sqlSessionFactoryBean的过程可以看出,mybaits默认使用spring的事务管理功能或者由第三方实现,它自身并没有提供事务管理能力。其次,它拥有跟其它框架差不多的解析xml过程,都是将xml解析成一个Configuration对象随时取用。到这里我们就得到了一个sqlSessionFactoryBean对象(实际是mybatis本身的DefaultSqlSessionFactory对象),我们可以在DAO中注入这个对象并利用openSession的方法获取SqlSession对象从而进行各种数据库操作。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多