@SpringBootApplication注解的生效的顺序

### @SpringBootApplication    有三个重要注解: 

1、 @SpringBootConfiguration
由于@SpringBootConfiguration标注了@Configuration注解,所以标注了此注解的类会被解析为bean注册到ioc容器中

具体流程:在SpringApplication.run().prepareContext()方法中,
          调用BeanDefinitionLoader.load()把主类解析成BeanDefinition保存到IOC容器中       
          
          
          
2、 @ComponentScan             加载时机在哪?refreshContext的invokeBeanFactoryPostProcessors

具体流程:在SpringApplication.run().refreshContext()方法中,   
-> AbstractApplicationContext.refresh()
    调用invokeBeanFactoryPostProcessors()
          
-> PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors()              
-> ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()
-> ConfigurationClassPostProcessor.processConfigBeanDefinitions()

    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
         
        1、String[] candidateNames = registry.getBeanDefinitionNames()                                    获取ioc容器中的所有bean定义
        2、ConfigurationClassUtils.checkConfigurationClassCandidate()                                     检测是ConfigurationClass注解类不,此时只有主类是
        3、configCandidates.isEmpty()                                                                     判断是否找到@Configuration标注的类,若没有就返回
              

        // Parse each @Configuration class
        ConfigurationClassParser parser = new ConfigurationClassParser(
                this.metadataReaderFactory, this.problemReporter, this.environment,
                this.resourceLoader, this.componentScanBeanNameGenerator, registry);
 
        do {
 
            4、parser.parse(candidates);                                                                   传入参数是主启动类 
             
            this.reader.loadBeanDefinitions(configClasses);
             
             
        }
     
    }
    
-> ConfigurationClassParser.parse(candidates)                                    
    public void parse(Set<BeanDefinitionHolder> configCandidates) {
        for (BeanDefinitionHolder holder : configCandidates) {                                          for循环主要处理@ComponentScan注解        
            BeanDefinition bd = holder.getBeanDefinition();
            try {
                if (bd instanceof AnnotatedBeanDefinition annotatedBeanDef) {
                    parse(annotatedBeanDef.getMetadata(), holder.getBeanName());
                }
                else if (bd instanceof AbstractBeanDefinition abstractBeanDef &&
                abstractBeanDef.hasBeanClass()) {
                    parse(abstractBeanDef.getBeanClass(), holder.getBeanName());
                }
                else {
                    parse(bd.getBeanClassName(), holder.getBeanName());
                }
                
                //   执行parse重载方法处理@Component、@PropertySources等注解
                  this.componentScanParser.parse                                                                处理@ComponentScan 
                  -> ComponentScanAnnotationParser.parse()
                      ClassUtils.getPackageName(declaringClass)                                                 从主类中获取主类所在的包路径
                  -> ClassPathBeanDefinitionScanner.doScan(StringUtils.toStringArray(basePackages))             扫描包路径,获取组件
                  -> ClassPathScanningCandidateComponentProvider.findCandidateComponents()
                  -> ClassPathScanningCandidateComponentProvider.scanCandidateComponents()                      把主类所在包的所有class文件加载到内存
                  -> ClassPathScanningCandidateComponentProvider..isCandidateComponent()                        循环判断class是否是组件,这里把
                                                                                                                     @ComponentScan、@Configuration标注的类都算
                  
                      for (TypeFilter tf : this.excludeFilters)                                                 excludeFilters里面有主类、
                                                                                                                  AutoConfigurationExcludeFilter、TypeExcludeFilter,排除掉
                      
                      for (TypeFilter tf : this.includeFilters)                                                 includeFilters里面有
                                                                                                                        interface org.springframework.steretope.Component、
                                                                                                                        interface jakarta.annotation.ManagedBean
                  
                        此时:候选组件扫描会把主类排除(主类以提前注册了),把@Component、@Configuration等标注的都作为候选
            }
            catch (BeanDefinitionStoreException ex) {
                throw ex;
            }
            catch (Throwable ex) {
                throw new BeanDefinitionStoreException( );
            }
        }

        
        this.deferredImportSelectorHandler.process();                                               处理@EnableAutoConfiguration的
                                                                                                    @Import(AutoConfigurationImportSelector.class) 
    }
              
                  
                  
                 
3、@EnableAutoConfiguration                    有两个功能:
                                                   第一:@Import(AutoConfigurationImportSelector.class)导入第三方包及其本身包中的spirng spi配置的组件
                                                   第二:@AutoConfigurationPackage给第三方一个路径,扫描路径下第三方的bean注册到ioc容器中

3.1 AutoConfigurationImportSelector 导入第三方包及其本身包中的spirng spi配置的组件  加载时机在哪?invokeBeanFactoryPostProcessors
具体流程: 
-> ConfigurationClassParser.parse(candidates)                                                    
  
  
    ...  
    this.deferredImportSelectorHandler.process()                                                 执行到最后一行
-> ConfigurationClassParser$DeferredImportSelectorHandler.process()
    handler.processGroupImports()
-> ConfigurationClassParser$DeferredImportSelectorGroupingHandler.processGroupImports()

    grouping.getImports().forEach(entry -> {  processImports() });                               注意:先执行getImports在执行processImports
                                

    
-> DeferredImportSelectorGrouping.getImports()
    this.group.process()
-> AutoConfigurationGroup.process()
-> AutoConfigurationImportSelector.getAutoConfigurationEntry()
      List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)    spring spi机制获取第三方自动配置类
      Set<String> exclusions = getExclusions(annotationMetadata, attributes)                      经过排除
      configurations = getConfigurationClassFilter().filter(configurations)                       过滤后交给processImports()
                        
-> ConfigurationClassParser.processImports()                                
               
                      
3.2 @AutoConfigurationPackage                它负责保存标注相关注解的类的所在包路径。使用一个BasePackage类,保存这个路径。
                                             然后使用@Import注解将其注入到ioc容器中。这样,可以在容器中拿到该路径。   
                                                      
    
具体流程
-> ConfigurationClassPostProcessor.processConfigBeanDefinitions()
    this.reader.loadBeanDefinitions(configClasses);                         此时ConfigurationClassParser.parse(candidates)已执行了
 
-> ConfigurationClassBeanDefinitionReader.loadBeanDefinitions()         循环遍历每个ConfigurationClass                                                                 
    public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
        TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
        for (ConfigurationClass configClass : configurationModel) {
            loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
        }
    }              

-> ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass() 

    private void loadBeanDefinitionsForConfigurationClass(
            ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

        if (trackedConditionEvaluator.shouldSkip(configClass)) {
            String beanName = configClass.getBeanName();
            if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
                this.registry.removeBeanDefinition(beanName);
            }
            this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
            return;
        }

        if (configClass.isImported()) {
            registerBeanDefinitionForImportedConfigurationClass(configClass);
        }
        for (BeanMethod beanMethod : configClass.getBeanMethods()) {
            loadBeanDefinitionsForBeanMethod(beanMethod);                                           处理类路径及框架的所有类中的@Bean
        }

        loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
        loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
    }

-> ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsFromRegistrars()                           调用到主类的AutoConfigurationPackages.Registrar
             
               把AutoConfigurationPackages作为bean定义存放到ioc容器,第三方就可以扫描这些路径,如mybatis

               
               
               
-> 在MybatisPlusAutoConfiguration$AutoConfiguredMapperScannerRegistrar.registerBeanDefinitions()
                List<String> packages = AutoConfigurationPackages.get(this.beanFactory)                            调用自动配置包路径,扫描Mapper

          


          
             
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值