• SpringBoot之处理@SpringBootApplication的两个import


    都知道注解SpringBootApplication有两个import

    1  @Import(AutoConfigurationImportSelector.class)

    2  @Import(AutoConfigurationPackages.Registrar.class)

    第一个的作用和原理我看网上说的挺多的,但是第二个貌似不多。今天我就分析分析@Import(AutoConfigurationPackages.Registrar.class)的作用

    先看看方法内的注解

    /**
     * Class for storing auto-configuration packages for reference later (e.g. by JPA entity
     * scanner).

      一个Class,保存了自动装配的包路径,为了后续引用的使用(例如JPA实体类的扫描)

      简单点说就是保存自动装配的路径的

      现在跟随代码看看它是怎么生效的

       ConfigurationClassPostProcessor.processConfigBeanDefinitions 代码片段

      

    do {
                parser.parse(candidates);
                parser.validate();
    
                Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
                configClasses.removeAll(alreadyParsed);
    
                // Read the model and create bean definitions based on its content
                if (this.reader == null) {
                    this.reader = new ConfigurationClassBeanDefinitionReader(
                            registry, this.sourceExtractor, this.resourceLoader, this.environment,
                            this.importBeanNameGenerator, parser.getImportRegistry());
                }
                this.reader.loadBeanDefinitions(configClasses);

      经过了parser解析之后,我们最终能得到configClasses这些都是带有@Configuration注解的

      本篇我们不分析  AutoConfigurationImportSelector 但是他的作用还是要提一下,在 parser.parse 就会完成对AutoConfigurationImportSelector的处理,也就是把各个包下的spring.factory里的自动装配相关的class都选出来。所以上面代码中configClasses多达76个。而我们的启动类只是其中之一。

    ConfigurationClass里有一个字段专门用来保存Registrar的。比如我们的启动类对应的 ConfigurationClass 就有两个 Registrar。除了自带的AutoConfigurationPackages.Registrar还有
    MapperScannerRegistrar那是因为在启动类里配了Mybatis的scan路径
      
    接下来就是分析  this.reader.loadBeanDefinitions(configClasses); 
      最终会执行  ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsFromRegistrars 
      
    private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
            registrars.forEach((registrar, metadata) ->
                    registrar.registerBeanDefinitions(metadata, this.registry));
        }
    AutoConfigurationPackages$Registrar
    static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
    
            @Override
            public void registerBeanDefinitions(AnnotationMetadata metadata,
                    BeanDefinitionRegistry registry) {
                register(registry, new PackageImport(metadata).getPackageName());
            }

      最终调用的是  AutoConfigurationPackages.register

    public static void register(BeanDefinitionRegistry registry, String... packageNames) {
            if (registry.containsBeanDefinition(BEAN)) { //跟代码的时候走不到这里
                BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
                ConstructorArgumentValues constructorArguments = beanDefinition
                        .getConstructorArgumentValues();
                constructorArguments.addIndexedArgumentValue(0,
                        addBasePackages(constructorArguments, packageNames));
            }
            else {
                GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
                beanDefinition.setBeanClass(BasePackages.class);
                beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0,
                        packageNames);
                beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
                registry.registerBeanDefinition(BEAN, beanDefinition);//就是注册个beanDefinition,类是 BasePackages
            }
        }

      这里的 packageNames 如果没有配的就是启动类所在的路径  

    二 被调用处

       AutoConfigurationPackages.get 该方法的作用就是返回上面提到的路径 我的这个例子就是 com.example.demo

    public static List<String> get(BeanFactory beanFactory) {
            try {
                return beanFactory.getBean(BEAN, BasePackages.class).get();
            }
            catch (NoSuchBeanDefinitionException ex) {
                throw new IllegalStateException(
                        "Unable to retrieve @EnableAutoConfiguration base packages");
            }
        }

      那么这个get又有啥作用呢

      我们以 AutoConfiguredMapperScannerRegistrar 为例

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    
          if (!AutoConfigurationPackages.has(this.beanFactory)) {
            logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.");
            return;
          }
    
          logger.debug("Searching for mappers annotated with @Mapper");
    
          List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
          if (logger.isDebugEnabled()) {
            packages.forEach(pkg -> logger.debug("Using auto-configuration base package '{}'", pkg));
          }

      拿到这个扫包根路径之后就可以扫包了

  • 相关阅读:
    个人总结
    第二次冲刺 10
    第二次冲刺 09
    第二次冲刺 08
    第二次冲刺 07
    团队冲刺第七天
    团队绩效评估
    团队冲刺第六天
    团队冲刺第五天
    团队冲刺第四天
  • 原文地址:https://www.cnblogs.com/juniorMa/p/14188119.html
Copyright © 2020-2023  润新知