spring源码学习之整合Mybatis原理分析

https://blog.csdn.net/lihuayong/article/details/83934744

总结简述:

  • <import resource="spring-mybatis.xml"/>
    • 在该xml 文档下配置如下
      • <!-- spring和MyBatis整合,不需要mybatis的配置映射文件 -->
        	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        		<property name="dataSource" ref="dataSource" />
        		<!-- 配置MyBaties全局配置文件:mybatis-config.xml -->
        		<property name="configLocation" value="classpath:sqlmap/mybatis-config.xml" />
        		<!-- 自动扫描mapping.xml文件 -->
        		<property name="mapperLocations">
        			<array>
        				<value>classpath:sqlmap/*/*.xml</value>
        			</array>
        		</property>
        	</bean>
        
        	<!-- DAO接口所在包名,Spring会自动查找其下的类 -->
        	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        		<property name="basePackage" value="com.em" />
        		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
        	</bean>

创建MapperScannerConfigurer

public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware
  • MapperScannerConfigurer 实现了BeanDefinitionRegistryPostProcessor 接口
    • 初始化时,会自动调用 postProcessBeanDefinitionRegistry 方法
    •   public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
          if (this.processPropertyPlaceHolders) {
            processPropertyPlaceHolders();
          }
      
          ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
          scanner.setAddToConfig(this.addToConfig);
          scanner.setAnnotationClass(this.annotationClass);
          scanner.setMarkerInterface(this.markerInterface);
          scanner.setSqlSessionFactory(this.sqlSessionFactory);
          scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
          scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
          scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
          scanner.setResourceLoader(this.applicationContext);
          scanner.setBeanNameGenerator(this.nameGenerator);
          scanner.registerFilters();
          scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
        }

       

    • ClassPathMapperScanner这个扫描器的主要的作用有以下几个:
      • 第一扫描basePackage包下面所有的class类
      • 第二将所有的class类封装成为spring的ScannedGenericBeanDefinition sbd对象
      • 第三过滤sbd对象,只接受接口类,从下面的代码中可以看出
        • isCandidateComponent
      • 第四完成sbd对象属性的设置,
        • 比如设置sqlSessionFactory、BeanClass等,
        • 这个sqlSessionFactory是本文接下来要解析的SqlSessionFactoryBean
        • 注意scanner
          ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
        • 所以ClassPathMapperScanner 的doScan 要覆盖掉父类的
          • 执行processBeanDefinitions,内部设置很关键(说明这里封装的Mapper 接口,都是mapperFactoryBean)
            • definition.setBeanClass(this.mapperFactoryBean.getClass());
            • 后续使用 这些Mapper 接口的时候,其实获取实例调用的是
            •   public T getObject() throws Exception {
                  return getSqlSession().getMapper(this.mapperInterface);
                }

               

      • 第五将过滤出来的sbd对象通过这个BeanDefinitionRegistry registry
        • 注册器注册到DefaultListableBeanFactory中

d4ab30e3442444d7b1a517bfae4a4caef40.jpg

创建SqlSessionFactoryBean

继承了FactoryBean<SqlSessionFactory>

  • 注意 FactoryBean的方法

89109d3b2f6f85ea81b9885ef6965d427fb.jpg

  • 由于继承了InitializingBean 所以bean被创建的过程中
    • 执行afterPropertiesSet方法

      • buildSqlSessionFactory
        • } else if (this.configLocation != null) {
                xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
                configuration = xmlConfigBuilder.getConfiguration();
              } 
        • return this.sqlSessionFactoryBuilder.build(configuration);
          • return new DefaultSqlSessionFactory(config);

97d4be51907f0deb863c580ebc42d90503c.jpg

执行onApplicationEvent方法

  • 用完上面的afterPropertiesSet方法之后,
  • 第二个被调用的就是onApplicationEvent方法,
  • 这个方法的调用时机是,spring容器初始化完成之后

执行getObject方法

  • 第三个被调用的就是getObject方法,
  • 该方法是接口FactoryBean<SqlSessionFactory>中的方法。
  • 这个方法的调用时机是?
  • 首先需要简单介绍一下这个FactoryBean的作用
    • Spring通过反射机制利用<bean>标签的class属性指定实现类实例化Bean
      • 过于繁杂
    • Spring为此提供了一个org.springframework.beans.factory.FactoryBean<T>的工厂类接口,
      • 我们可以通过实现该接口定制实例化Bean的逻辑。
  • 实现了FactoryBean<T>接口的Bean,不同于普通Bean,
    • 根据该Bean的ID从BeanFactory中获取的
    • 实际上是FactoryBean的getObject()返回的对象,
    • 而不是FactoryBean本身,
      • 如果要获取FactoryBean对象,请在id前面加一个&符号来获取。

 

转载于:https://my.oschina.net/u/3847203/blog/3019774

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值