spring源碼學習之整合Mybatis原理分析

http://www.javashuo.com/article/p-nrernvil-dk.htmljava

總結簡述:spring

  • <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中

建立SqlSessionFactoryBean

繼承了FactoryBean<SqlSessionFactory>sql

  • 注意 FactoryBean的方法

  • 因爲繼承了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);

執行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前面加一個&符號來獲取。
相關文章
相關標籤/搜索