Mybatis是如何读取配置并将指定路径的类转化为BeanDefinition的

首先以ImportBeanDefinitionRegistrar(MapperScannerRegistrar) 将@MapperScan注解及其属性转化为BeanDefinitionRegistryPostProcessor(MapperScannerConfigurer)

BeanDefinitionRegistryPostProcessor(MapperScannerConfigurer) 将配置交给扫描器处理转换成BeanDefinition

以import的方式导入MapperScannerRegistrar

@Import(MapperScannerRegistrar.class)

会将指定的类实例化为bean

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {
    // 省略
}

MapperScannerRegistrar将配置转化为一个BeanDefinition(MapperScannerConfigurer)

MapperScannerRegistrar继承了 ImportBeanDefinitionRegistrar,

ImportBeanDefinitionRegistrar会在容器启动,尝试创建BeanDefinition的时候调用

 /**
  * AnnotationMetadata importingClassMetadata, 带有@Configuration注解的类
  * BeanDefinitionRegistry registry BeanDefinition注册器
  */

@Override
 public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    AnnotationAttributes mapperScanAttrs = AnnotationAttributes
        .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
    if (mapperScanAttrs != null) {
        // 这里指定一定要带有MapperScan.class注解
      registerBeanDefinitions(mapperScanAttrs, registry, generateBaseBeanName(importingClassMetadata, 0));
    }
  }

void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) {

    BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
    // 省略中间与本次问题无关的代码....
    
    // 获取需要扫描路径
    List<String> basePackages = new ArrayList<>();
    basePackages.addAll(
        Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));

    basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText)
        .collect(Collectors.toList()));

    basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName)
        .collect(Collectors.toList()));

    builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));

    // 这里生成了一个 MapperScannerRegistrar的BeanDefinition并注册,并且将@MapperScan注解里的属性都记录在该BeanDefinition中
    registry.registerBeanDefinition(beanName, builder.getBeanDefinition());

  }

MapperScannerConfigurer将指定配置中的类转换为BeanDefinition

MapperScannerConfigurer继承了 BeanDefinitionRegistryPostProcessor

注意:BeanDefinitionRegistryPostProcessor 继承自 BeanFactoryPostProcessor,比 BeanFactoryPostProcessor 具有更高的优先级

  @Override
  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.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
    if (StringUtils.hasText(lazyInitialization)) {
      scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
    }
    scanner.registerFilters();
    scanner.scan(
        StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
  }

问:既然我们在ImportBeanDefinitionRegistrar的时候就能拿到注解的属性,那为什么不直接就生成对应配置的BeanDefinition,还要多一步呢?

我看老版本的mybatis的确是在第一步直接读取配置并直接扫描路径的,新版本的才多了一步,我使用的版本是3.5.2。

在新版本中多了属性占位符替换这么一步

因此猜测是为了支持@Configuration配置属性的占位符配置功能,

在MapperScannerConfigurer该类的doc文档上也的确有注释。

BeanDefinitionRegistries 在应用程序启动的早期,并且在BeanFactoryPostProcessors 之前被调用。这意味着将不会加PropertyResourceConfigurers,并且此类属性的任何属性替换都将失败。为了避免这种情况,找到上下文中定义的任何 PropertyResourceConfigurers 并在此类的 bean 定义上运行它们。然后更新值。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值