mybatis-spring整合源碼解析

Mybatis對(duì)Spring的整合實(shí)現(xiàn)

本文只討論整合Spring,Mybatis是如何整合到Spring生態(tài)中的

接口掃描的MapperScan的實(shí)現(xiàn)和擴(kuò)展

@MapperScan, 元標(biāo)注了@Import注解,導(dǎo)入了一個(gè)MapperScannerRegistrarConfiguration Class , 申明如下

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware

我們都知道ImportBeanDefinitionRegistrar 是Spring注入Configuration Class到容器中的一種常見手段, 常見的還有@Import,ImportSelector.. , 該實(shí)現(xiàn)類的核心邏輯在registerBeanDefinitions()中,如下

 //importingClassMetadata 為當(dāng)前標(biāo)注了@Import的Configuration Class的注解元信息
//BeanDefinitionRegistry registry 為當(dāng)前BeanFacatory的引用
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
   //1. 獲取@MapperScan注解的屬性信息
    AnnotationAttributes mapperScanAttrs = AnnotationAttributes
        .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
    if (mapperScanAttrs != null) {
     // 2. 注冊(cè)一個(gè)名為 MapperScannerConfigurer的 Bean到IOC容器中
      registerBeanDefinitions(mapperScanAttrs, registry, generateBaseBeanName(importingClassMetadata, 0));
    }
  }
    
  // 具體注冊(cè)Bean的邏輯
  void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) {
        //1. 構(gòu)造BeanDefinition
    BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
    builder.addPropertyValue("processPropertyPlaceHolders", true);
        //2. 設(shè)置自定義的注解,在后面自定義掃描有大用處
    Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
    if (!Annotation.class.equals(annotationClass)) {
      builder.addPropertyValue("annotationClass", annotationClass);
    }
        //3. 設(shè)置自定義的接口 Class,在后面自定義掃描有大用處
    Class<?> markerInterface = annoAttrs.getClass("markerInterface");
    if (!Class.class.equals(markerInterface)) {
      builder.addPropertyValue("markerInterface", markerInterface);
    }
    
    //....省略部分PropertyValues的屬性賦值

MapperScannerConfigurer的用處以及實(shí)現(xiàn)原理

是一個(gè)BeanDefinitionRegistryPostProcessor的實(shí)現(xiàn)類,該類型會(huì)在Spring容器啟動(dòng)刷新時(shí)進(jìn)行回調(diào)

查看源碼發(fā)現(xiàn)其類的聲明如下

//1. 發(fā)現(xiàn)其是一個(gè)BeanDefinitionRegistryPostProcessor , 該類型接口會(huì)在IOC容器刷新的時(shí)候進(jìn)行回調(diào)
public class MapperScannerConfigurer
    implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware
  
//2. 能在回調(diào)方法中發(fā)現(xiàn)其核心做了兩件事情
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    if (this.processPropertyPlaceHolders) {
      processPropertyPlaceHolders(); //解析相關(guān)包名占位符
    }
        //2.1 創(chuàng)建自定義的ClassPathBeanDefinitionScanner(Spring中@ComponentScan核心處理類)并添加自定義的掃描類型
    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.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
    if (StringUtils.hasText(lazyInitialization)) {
      scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
    }
    scanner.registerFilters();
   //2.2 進(jìn)行掃描獲取BeanDefinition,并注冊(cè)到容器中
    scanner.scan(
        StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
  }

接下來(lái)我們來(lái)看ClassPathMapperScanner組件的用處 , 他其實(shí)是擴(kuò)展了spring的@ComponentScan的組件掃描方式,核心看registerFilters()方法,里面添加了要掃描的TypeFilter的方式

  public void registerFilters() {
    boolean acceptAllInterfaces = true; //1. 這個(gè)標(biāo)志位是否要掃描包下所有的接口
        
        //2. 這里的annotationClass是前面注冊(cè)MapperScannerConfigurer時(shí)傳遞進(jìn)來(lái)的自定義注解屬性
    if (this.annotationClass != null) {
        // 2.1 這里添加IncludeFilter表示,要添加一個(gè)允許的掃描注解,只要標(biāo)注了該注解就會(huì)被ClassLoader掃描到
      addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
      acceptAllInterfaces = false;
    }

        //3. 這里的annotationClass是前面注冊(cè)MapperScannerConfigurer時(shí)傳遞進(jìn)來(lái)的自定義接口Class
    if (this.markerInterface != null) {
      //3.1 掃描自定義的接口類型,并且
      addIncludeFilter(new AssignableTypeFilter(this.markerInterface) {
        @Override
        protected boolean matchClassName(String className) {
          //不能實(shí)現(xiàn)類Class,只能是抽象接口或者抽象類
          return false;
        }
      });
      acceptAllInterfaces = false;
    }
        //4. 如果沒(méi)有自定義注解或者自定義接口掃描,那么添加一個(gè)TypeFilter默認(rèn)全部掃描所有
    if (acceptAllInterfaces) {
      // default include filter that accepts all classes
      addIncludeFilter((metadataReader, metadataReaderFactory) -> true);
    }

    // exclude package-info.java
    addExcludeFilter((metadataReader, metadataReaderFactory) -> {
      String className = metadataReader.getClassMetadata().getClassName();
      return className.endsWith("package-info");
    });
  }

掃描時(shí)如何根據(jù)IncludeFilter/ExcludeFilter進(jìn)行掃描和過(guò)濾?核心方法調(diào)用鏈如下

//調(diào)用鏈
//ClassPathMapperScanner#doScan() -> ClassPathBeanDefinitionScanner#doScan() -> ClassPathScanningCandidateComponentProvider#findCandidateComponents()  -> scanCandidateComponents()
 
 //其中scanCandidateComponents()方法具體實(shí)現(xiàn)如下
  private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
        Set<BeanDefinition> candidates = new LinkedHashSet<>();
        try {
            //1. 獲取傳遞進(jìn)來(lái)的掃描包路徑
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    resolveBasePackage(basePackage) + '/' + this.resourcePattern;
      //2. 使用ResourceLoader加載資源
            Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
            boolean traceEnabled = logger.isTraceEnabled();
            boolean debugEnabled = logger.isDebugEnabled();
            for (Resource resource : resources) {
                if (traceEnabled) {
                    logger.trace("Scanning " + resource);
                }
                if (resource.isReadable()) {
                    try {
           //3. 使用ASM進(jìn)行元信息讀取
                        MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
            //4. 這里很關(guān)鍵里面會(huì)進(jìn)行IncludeFilter和ExcludeFilter的判斷,也是能自定義擴(kuò)展組件掃描的核心方法
                        if (isCandidateComponent(metadataReader)) {
            // 5. 拼裝成BeanDefinition,后面會(huì)給BeanDefinition設(shè)置beanClass為MapperFactoryBean代理對(duì)象
             //6. 最后注冊(cè)到IOC容器中,此時(shí)我們已經(jīng)可以使用Mybatis的Mapper來(lái)完成依賴注入和依賴查找了
                            ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                            sbd.setSource(resource);
                            if (isCandidateComponent(sbd)) {
                                if (debugEnabled) {
                                    logger.debug("Identified candidate component class: " + resource);
                                }
                                candidates.add(sbd);
                            }
    //省略部分無(wú)關(guān)源碼...

其中isCandidateComponent()實(shí)現(xiàn)如下

    protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
        for (TypeFilter tf : this.excludeFilters) { //遍歷所有的ExcludeFilter,若有匹配的則返回false不進(jìn)行掃描
            if (tf.match(metadataReader, getMetadataReaderFactory())) {
                return false;
            }
        }
            //遍歷所有的IncludeFilter,若匹配則進(jìn)行Conditional條件注解判斷,這里includeFilters中就包括了之前
            //ClassPathMapperScanner#registerFilters()方法中注冊(cè)的includeFilters。這也是為什么我們配置了
            // @MapperScan(basePakages="xxxx")就能掃描到xxx包下的所有類到ioc容器中的所有原理
        for (TypeFilter tf : this.includeFilters) { 
            if (tf.match(metadataReader, getMetadataReaderFactory())) {
                return isConditionMatch(metadataReader);
            }
        }
        return false;
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容