6套源码系列Spring,Mybatis,Springboot,Netty源码深度解析

下面将结合mybatis源码来分析下,这种持久化框架是如何对connection使用,来达到spring事务的控制。

想要在把mybatis跟spring整合都需要这样一个jar包:mybatis-spring-x.x.x.jar,这里面定义了一些主要的整合信息。

在spring配置文件中需要配置如下两个bean:

复制代码

    <!-- mybatis配置 -->     <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">         <property name="dataSource" ref="dynamicDataSource" />         <property name="configLocation" value="classpath:mybatis.xml"></property>         <!-- mybatis配置文件 -->         <property name="mapperLocations" value="classpath:com/blackbread/dao/mapper/*.xml" />     </bean>     <!--mapper scanning -->     <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">         <property name="basePackage" value="com.blackbread.dao" />         <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />     </bean>

复制代码

首先让我们来看org.mybatis.spring.SqlSessionFactoryBean,在这个类需要注入跟之前tx配置中一样的dataSource。

SqlSessionFactoryBean类实现了InitializingBean接口,所以会执行afterPropertiesSet方法,在afterPropertiesSet方法中会执行buildSqlSessionFactory方法生成一个sqlSessionFactory对象,让我们看下buildSqlSessionFactory方法:由于主要看的是跟spring tx结合的方式,所以代码看不上很细,如有疏漏,望不吝赐教。

复制代码

      protected SqlSessionFactory buildSqlSessionFactory() throws IOException {             Configuration configuration;             XMLConfigBuilder xmlConfigBuilder = null;             //初始化一个configuration             if (this.configLocation != null) {               xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);               configuration = xmlConfigBuilder.getConfiguration();             } else {               configuration = new Configuration();               configuration.setVariables(this.configurationProperties);             }             if (this.objectFactory != null) {               configuration.setObjectFactory(this.objectFactory);             }             if (this.objectWrapperFactory != null) {               configuration.setObjectWrapperFactory(this.objectWrapperFactory);             }             if (hasLength(this.typeAliasesPackage)) {               String[] typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage,                   ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);               for (String packageToScan : typeAliasPackageArray) {                 configuration.getTypeAliasRegistry().registerAliases(packageToScan,                         typeAliasesSuperType == null ? Object.class : typeAliasesSuperType);               }             }             //设置别名             if (!isEmpty(this.typeAliases)) {               for (Class<?> typeAlias : this.typeAliases) {                 configuration.getTypeAliasRegistry().registerAlias(typeAlias);               }             }             //装入插件,mybatis的插件都是以拦截器的形式进行的好像,比如分页插件,这里是载入spring中注入的             if (!isEmpty(this.plugins)) {               for (Interceptor plugin : this.plugins) {                 configuration.addInterceptor(plugin);               }             }             if (hasLength(this.typeHandlersPackage)) {               String[] typeHandlersPackageArray = tokenizeToStringArray(this.typeHandlersPackage,                   ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);               for (String packageToScan : typeHandlersPackageArray) {                 configuration.getTypeHandlerRegistry().register(packageToScan);               }             }             if (!isEmpty(this.typeHandlers)) {               for (TypeHandler<?> typeHandler : this.typeHandlers) {                 configuration.getTypeHandlerRegistry().register(typeHandler);               }             }             //这里将解析mybatis.xml文件,载入所有配置,插件、setting等             if (xmlConfigBuilder != null) {               try {                 xmlConfigBuilder.parse();               } catch (Exception ex) {                 throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);               } finally {                 ErrorContext.instance().reset();               }             }             //这个很重要,这里定义了用的transactionFactory为SpringManagedTransactionFactory,这个在获取             //connection等地方都有用到,是mybatis跟spring的主要链接             if (this.transactionFactory == null) {               this.transactionFactory = new SpringManagedTransactionFactory();             }             //新建一个Environment对象,并将新建的transactionFactory放入其中             Environment environment = new Environment(this.environment, this.transactionFactory, this.dataSource);             configuration.setEnvironment(environment);             if (this.databaseIdProvider != null) {               try {                 configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));               } catch (SQLException e) {                 throw new NestedIOException("Failed getting a databaseId", e);               }             }             if (!isEmpty(this.mapperLocations)) {               for (Resource mapperLocation : this.mapperLocations) {                 if (mapperLocation == null) {                   continue;                 }                 try {                 //这里主要是解析配置的sql 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();                 }               }             } else {               }             }             return this.sqlSessionFactoryBuilder.build(configuration);           }

复制代码

看着好长的一段啊,其实这里做的工作就是解析配置文件生成configuration对象而已。在

 xmlMapperBuilder.parse();

这里将解析sql mapper文件中的映射关系生成MappedStatement对象,并执行 configuration.addMappedStatement(statement);放入到configuration对象中,有兴趣的同学可以仔细看下。

这里主要需要注意的一块就是this.transactionFactory = new SpringManagedTransactionFactory();这里就是mybatis跟spring连接到一起的地方。

接着我们看一下org.mybatis.spring.mapper.MapperScannerConfigurer对象的初始化过程,这个对象实现了BeanDefinitionRegistryPostProcessor接口,在postProcessBeanDefinitionRegistry方法中初始化一个对象ClassPathMapperScanner,并讲执行scan--->doScan方法,

复制代码

public Set<BeanDefinitionHolder> doScan(String... basePackages) {         Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);           for (BeanDefinitionHolder holder : beanDefinitions) {             GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();             definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName());             //实际就是将扫描到的接口包装成MapperFactoryBean的实现类             definition.setBeanClass(MapperFactoryBean.class);             definition.getPropertyValues().add("addToConfig", this.addToConfig);             boolean explicitFactoryUsed = false;             //注入sqlSessionFactory对象,这个也很重要             if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {               definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));               explicitFactoryUsed = true;             } else if (this.sqlSessionFactory != null) {               definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);               explicitFactoryUsed = true;             }             if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {               if (explicitFactoryUsed) {                 logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");               }               definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));               explicitFactoryUsed = true;             } else if (this.sqlSessionTemplate != null) {               if (explicitFactoryUsed) {                 logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");               }               definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);               explicitFactoryUsed = true;             }             if (!explicitFactoryUsed) {               definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);             }           }         return beanDefinitions;       }

复制代码

这段代码其实主要就是从basePackage中扫描到相应的接口类,并且注册到spring中,并且定义此对象的FactoryBean为:MapperFactoryBean,将返回如下对象


猜你喜欢

转载自blog.51cto.com/14183709/2375049