为了账号安全,请及时绑定邮箱和手机立即绑定

Spring源码解析 – @Configuration配置类及注解Bean的解析

标签:
Java

在分析Spring 容器创建过程时,我们知道容器默认会加载一些后置处理器PostPRocessor,以AnnotationConfigApplicationContext为例,在构造函数中初始化reader时,加载默认后置处理器。其中 ConfigurationClassPostProcessor这个后置处理器专门处理带有@Configuration注解的类,ConfigurationClassPostProcessor后置处理实现了BeanDefinitionRegistryPostProcessor接口和PriorityOrdered接口,所以会在容器初始化refres()方法中执行后置处理器时优先执行,主要负责解析所有@Configuration标签类,并将Bean定义注册到容器中。

BeanDefinitionRegistryPostProcessor解析配置类过程:

复制代码

 1 public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { 2 //生成唯一标识,用于重复处理验证 3    int registryId = System.identityHashCode(registry); 4    if (this.registriesPostProcessed.contains(registryId)) { 5       throw new IllegalStateException( 6             "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry); 7    } 8    if (this.factoriesPostProcessed.contains(registryId)) { 9       throw new IllegalStateException(10             "postProcessBeanFactory already called on this post-processor against " + registry);11    }12    this.registriesPostProcessed.add(registryId);13    //解析Java类配置bean14    processConfigBeanDefinitions(registry);15 }

复制代码

processConfigBeanDefinitions(registry)处理逻辑:

复制代码

  1 public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {  2    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();  3   //所有已经注册的bean   4    String[] candidateNames = registry.getBeanDefinitionNames();  5    //遍历bean定义信息  6    for (String beanName : candidateNames) {  7       BeanDefinition beanDef = registry.getBeanDefinition(beanName);  8       if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||  9             ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) { 10          if (logger.isDebugEnabled()) { 11             logger.debug("Bean definition has already been processed as a configuration class: " + beanDef); 12          } 13       } 14   //如果当前的bean是Javabean配置类(含有@Configuration注解的类),则加入到集合configCandidates中, 15       else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) { 16          configCandidates.add(new BeanDefinitionHolder(beanDef, beanName)); 17       } 18    } 19  20    // Return immediately if no @Configuration classes were found 21   // 没有@Configuration注解的类,直接退出 22    if (configCandidates.isEmpty()) { 23       return; 24    } 25  26    // 多个Java配置类,按@Ordered注解排序 27    configCandidates.sort((bd1, bd2) -> { 28       int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition()); 29       int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition()); 30       return Integer.compare(i1, i2); 31    }); 32  33    // Detect any custom bean name generation strategy supplied through the enclosing application context 34    SingletonBeanRegistry sbr = null; 35    if (registry instanceof SingletonBeanRegistry) { 36       sbr = (SingletonBeanRegistry) registry; 37       if (!this.localBeanNameGeneratorSet) { 38          BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR); 39          if (generator != null) { 40             this.componentScanBeanNameGenerator = generator; 41             this.importBeanNameGenerator = generator; 42          } 43       } 44    } 45  46    if (this.environment == null) { 47       this.environment = new StandardEnvironment(); 48    } 49  50    // Parse each @Configuration class 51   //初始化一个ConfigurationClassParser解析器,可以解析@Congiguration配置类 52    ConfigurationClassParser parser = new ConfigurationClassParser( 53          this.metadataReaderFactory, this.problemReporter, this.environment, 54          this.resourceLoader, this.componentScanBeanNameGenerator, registry); 55  56    Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates); 57    Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size()); 58    do { 59     //1.解析Java配置类 60       parser.parse(candidates); 61     //主要校验配置类不能使用final修饰符(CGLIB代理是生成一个子类,因此原先的类不能使用final修饰) 62       parser.validate(); 63  64       //排除已处理过的配置类 65       Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses()); 66       configClasses.removeAll(alreadyParsed); 67         68       // Read the model and create bean definitions based on its content 69       if (this.reader == null) { 70          this.reader = new ConfigurationClassBeanDefinitionReader( 71                registry, this.sourceExtractor, this.resourceLoader, this.environment, 72                this.importBeanNameGenerator, parser.getImportRegistry()); 73       } 74     //2.加载bean定义信息,主要实现将@Configuration @Import @ImportResource @ImportRegistrar注册为bean 75       this.reader.loadBeanDefinitions(configClasses); 76       alreadyParsed.addAll(configClasses); 77       //清空已处理的配置类 78       candidates.clear(); 79     //再次获取容器中bean定义数量  如果大于 之前获取的bean定义数量,则说明有新的bean注册到容器中,需要再次解析 80       if (registry.getBeanDefinitionCount() > candidateNames.length) { 81          String[] newCandidateNames = registry.getBeanDefinitionNames(); 82          Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames)); 83          Set<String> alreadyParsedClasses = new HashSet<>(); 84          for (ConfigurationClass configurationClass : alreadyParsed) { 85             alreadyParsedClasses.add(configurationClass.getMetadata().getClassName()); 86          } 87          for (String candidateName : newCandidateNames) { 88             if (!oldCandidateNames.contains(candidateName)) { 89                BeanDefinition bd = registry.getBeanDefinition(candidateName); 90           //新注册的bean如果也是@Configuration配置类,则添加到数据,等待解析 91                if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) && 92                      !alreadyParsedClasses.contains(bd.getBeanClassName())) { 93                   candidates.add(new BeanDefinitionHolder(bd, candidateName)); 94                } 95             } 96          } 97          candidateNames = newCandidateNames; 98       } 99    }100    while (!candidates.isEmpty());101 102    // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes103    if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {104       sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());105    }106 107    if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {108       // Clear cache in externally provided MetadataReaderFactory; this is a no-op109       // for a shared cache since it'll be cleared by the ApplicationContext.110       ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();111    }112 }

复制代码

1.解析Java配置类parser.parse(candidates)

parser.parse(candidates)方法最终调用processConfigurationClass方法来处理@Configuration配置类,ConfigurationClassParser. processConfigurationClass()方法实现代码如下:

复制代码

 1 protected void processConfigurationClass(ConfigurationClass configClass) throws IOException { 2   //判断是否需要解析 3    if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) { 4       return; 5    } 6    //判断同一个配置类是否重复加载过,如果重复加载过,则合并,否则从集合中移除旧的配置类,后续逻辑将处理新的配置类 7    ConfigurationClass existingClass = this.configurationClasses.get(configClass); 8    if (existingClass != null) { 9       if (configClass.isImported()) {10          if (existingClass.isImported()) {11             existingClass.mergeImportedBy(configClass);12          }13          // Otherwise ignore new imported config class; existing non-imported class overrides it.14          return;15       }16       else {17          // Explicit bean definition found, probably replacing an import.18          // Let's remove the old one and go with the new one.19          this.configurationClasses.remove(configClass);20          this.knownSuperclasses.values().removeIf(configClass::equals);21       }22    }23 24    // Recursively process the configuration class and its superclass hierarchy.25    SourceClass sourceClass = asSourceClass(configClass);26    do {27      //【真正解析配置类】28       sourceClass = doProcessConfigurationClass(configClass, sourceClass);29    }30    while (sourceClass != null);31    //再次添加到到集合中32    this.configurationClasses.put(configClass, configClass);33 }

复制代码

doProcessConfigurationClass方法主要实现从配置类中解析所有bean,包括处理内部类,父类以及各种注解

ConfigurationClassParser. doProcessConfigurationClass()解析配置类逻辑如下:

复制代码

 1 protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) 2       throws IOException { 3  4    //递归处理任何成员(嵌套)类 5    processMemberClasses(configClass, sourceClass); 6  7    // 处理@PropertySource注解 8    for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable( 9          sourceClass.getMetadata(), PropertySources.class,10          org.springframework.context.annotation.PropertySource.class)) {11       if (this.environment instanceof ConfigurableEnvironment) {12          processPropertySource(propertySource);13       }14       else {15          logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +16                "]. Reason: Environment must implement ConfigurableEnvironment");17       }18    }19 20    // 处理@ComponentScan 
21 //获取@ComponentScan注解信息22    Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(23          sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);24    if (!componentScans.isEmpty() &&25          !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {26       for (AnnotationAttributes componentScan : componentScans) {27 28          // 按@CmponentScan注解扫描bean29          Set<BeanDefinitionHolder> scannedBeanDefinitions =30                this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());31          // 遍历扫描出的bean定义是否是配置类bean32          for (BeanDefinitionHolder holder : scannedBeanDefinitions) {33             BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();34             if (bdCand == null) {35                bdCand = holder.getBeanDefinition();36             }37 //若果扫描出的bean定义是配置类(含有@COnfiguration),则继续调用parse方法,内部再次调用doProcessConfigurationClas(),递归解析38             if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {39                parse(bdCand.getBeanClassName(), holder.getBeanName());40             }41          }42       }43    }44 45    //处理@Import注解46    processImports(configClass, sourceClass, getImports(sourceClass), true);47 48    //处理@ImportResource注解49    AnnotationAttributes importResource =50          AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);51    if (importResource != null) {52       String[] resources = importResource.getStringArray("locations");53       Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");54       for (String resource : resources) {55          String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);56          configClass.addImportedResource(resolvedResource, readerClass);57       }58    }59 60    //处理@Bean注解 61    Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);62    for (MethodMetadata methodMetadata : beanMethods) {63 //将解析出的所有@Bean注解方法添加到configClass配置类信息中64       configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));65    }66 67    //处理接口中所有添加@Bean注解的方法,内部通过遍历所有接口,解析得到@Bean注解方法,并添加到configClass配置类信息中68    processInterfaces(configClass, sourceClass);69 70    // 如果有父类,则返回父类,递归执行doProcessConfigurationClass()解析父类71    if (sourceClass.getMetadata().hasSuperClass()) {72       String superclass = sourceClass.getMetadata().getSuperClassName();73       if (superclass != null && !superclass.startsWith("java") &&74             !this.knownSuperclasses.containsKey(superclass)) {75          this.knownSuperclasses.put(superclass, configClass);76          // Superclass found, return its annotation metadata and recurse77          return sourceClass.getSuperClass();78       }79    }80 81    // No superclass -> processing is complete82    return null;83 }

复制代码

下面看两个很重要的注解@Bean和@ComponentScan的实现过程

@ComponentScan注解解析过程

Set<BeanDefinitionHolder> scannedBeanDefinitions =               this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());

@ComponentScan注解解析,从上面的代码可以看出@ComponentScan注解解析通过调用ComponentScanAnnotationParser的parse方法完成,而parse()方法内部处理了一些scanner属性(过滤器设置)和basePackages包名处理,最终通过调用ClassPathBeanDefinitionScanner.doScan方法实现扫面工作

复制代码

 1 public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) { 2    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry, 3          componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader); 4  5    Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator"); 6    boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass); 7    scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator : 8          BeanUtils.instantiateClass(generatorClass)); 9 10    ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");11    if (scopedProxyMode != ScopedProxyMode.DEFAULT) {12       scanner.setScopedProxyMode(scopedProxyMode);13    }14    else {15       Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");16       scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));17    }18 19    scanner.setResourcePattern(componentScan.getString("resourcePattern"));20 21    for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {22       for (TypeFilter typeFilter : typeFiltersFor(filter)) {23          scanner.addIncludeFilter(typeFilter);24       }25    }26    for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {27       for (TypeFilter typeFilter : typeFiltersFor(filter)) {28          scanner.addExcludeFilter(typeFilter);29       }30    }31 32    boolean lazyInit = componentScan.getBoolean("lazyInit");33    if (lazyInit) {34       scanner.getBeanDefinitionDefaults().setLazyInit(true);35    }36 37    Set<String> basePackages = new LinkedHashSet<>();38    String[] basePackagesArray = componentScan.getStringArray("basePackages");39    for (String pkg : basePackagesArray) {40       String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),41             ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);42       Collections.addAll(basePackages, tokenized);43    }44    for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {45       basePackages.add(ClassUtils.getPackageName(clazz));46    }47    if (basePackages.isEmpty()) {48       basePackages.add(ClassUtils.getPackageName(declaringClass));49    }50 51    scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {52       @Override53       protected boolean matchClassName(String className) {54          return declaringClass.equals(className);55       }56    });57    return scanner.doScan(StringUtils.toStringArray(basePackages));58 }

复制代码

View Code

doScan扫描basePackages下所有bean

复制代码

 1 protected Set<BeanDefinitionHolder> doScan(String... basePackages) { 2    Assert.notEmpty(basePackages, "At least one base package must be specified"); 3    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>(); 4    for (String basePackage : basePackages) { 5     //根据basePackage加载包下所有java文件,并扫描出所有bean组件, findCandidateComponents方法内部调用ClassPathScanningCandidateComponentProvider.scanCandidateComponents(backPackages) 6       Set<BeanDefinition> candidates = findCandidateComponents(basePackage); 7     //遍历beandefition 8       for (BeanDefinition candidate : candidates) { 9       //解析作用域Scope10          ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);11          candidate.setScope(scopeMetadata.getScopeName());12          String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);13 //14          if (candidate instanceof AbstractBeanDefinition) {15             postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);16          }17       //通用注解解析到candidate结构中,主要是处理Lazy, primary DependsOn, Role ,Description这五个注解18          if (candidate instanceof AnnotatedBeanDefinition) {19             AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);20          }21       //检查当前bean是否已经注册,不存在则注册22          if (checkCandidate(beanName, candidate)) {23             BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);24             definitionHolder =25                   AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);26             beanDefinitions.add(definitionHolder);27         // 注册到ioc容器中,主要是一些@Component组件,@Bean注解方法并没有在此处注册, definitionHolder: beanname和beandefinition 键值对28             registerBeanDefinition(definitionHolder, this.registry);29          }30       }31    }32    return beanDefinitions;33 }

复制代码

ClassPathBeanDefinitionScanner.scanCandidateComponents实现bean定义信息扫描

复制代码

 1 private Set<BeanDefinition> scanCandidateComponents(String basePackage) { 2    Set<BeanDefinition> candidates = new LinkedHashSet<>(); 3    try { 4     // @ComponentScan("com.sl.springlearning.extension")包路径处理:packageSearchPath = classpath*:com/sl/springlearning/extension/**/*.class 5       String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + 6             resolveBasePackage(basePackage) + '/' + this.resourcePattern; 7     //获取当前包下所有的class文件 8       Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath); 9       boolean traceEnabled = logger.isTraceEnabled();10       boolean debugEnabled = logger.isDebugEnabled();11       for (Resource resource : resources) {12          if (traceEnabled) {13             logger.trace("Scanning " + resource);14          }15          if (resource.isReadable()) {16             try {17                MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);18           //按照scanner过滤器过滤,比如配置类本身将被果过滤掉,没有@Component等组件注解的类将过滤掉19                if (isCandidateComponent(metadataReader)) {20                   ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);21                   sbd.setResource(resource);22                   sbd.setSource(resource);23                   if (isCandidateComponent(sbd)) {24                      if (debugEnabled) {25                         logger.debug("Identified candidate component class: " + resource);26                      }27                      candidates.add(sbd);28                   }29                   else {30                      if (debugEnabled) {31                         logger.debug("Ignored because not a concrete top-level class: " + resource);32                      }33                   }34                }35                else {36                   if (traceEnabled) {37                      logger.trace("Ignored because not matching any filter: " + resource);38                   }39                }40             }41             catch (Throwable ex) {42                throw new BeanDefinitionStoreException(43                      "Failed to read candidate component class: " + resource, ex);44             }45          }46          else {47             if (traceEnabled) {48                logger.trace("Ignored because not readable: " + resource);49             }50          }51       }52    }53    catch (IOException ex) {54       throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);55    }56    return candidates;57 }

复制代码

@Bean注解解析过程

retrieveBeanMethodMetadata方法实现了@Bean方法的解析,并未将实现bean实例的创建。

复制代码

 1 private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) { 2    AnnotationMetadata original = sourceClass.getMetadata(); 3 //获取所有@Bean注解的方法 4    Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName()); 5 // 如果配置类中有多个@Bean注解的方法,则排序 6    if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) { 7       // Try reading the class file via ASM for deterministic declaration order... 8       // Unfortunately, the JVM's standard reflection returns methods in arbitrary 9       // order, even between different runs of the same application on the same JVM.10       try {11          AnnotationMetadata asm =12                this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();13          Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());14          if (asmMethods.size() >= beanMethods.size()) {15             Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());16             for (MethodMetadata asmMethod : asmMethods) {17                for (MethodMetadata beanMethod : beanMethods) {18                   if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {19                      selectedMethods.add(beanMethod);20                      break;21                   }22                }23             }24             if (selectedMethods.size() == beanMethods.size()) {25                // All reflection-detected methods found in ASM method set -> proceed26                beanMethods = selectedMethods;27             }28          }29       }30       catch (IOException ex) {31          logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);32          // No worries, let's continue with the reflection metadata we started with...33       }34    }35    return beanMethods;36 }

复制代码

2.加载bean定义信息  this.reader.loadBeanDefinitions(configClasses)

  ConfigurationClassBeanDefinitionReader.loadBeanDefinitions()方法的功能就是将之前解析出的configClasses配置类信息中所有配置相关的信息添加到spring的bean定义,主要是配置类中的@Bean注解方法,配置类@ImportResource和@Import(实现ImportBeanDefinitionRegistrar接口方式)的bean注册

ConfigurationClassBeanDefinitionReader.loadBeanDefinitions()方法 实现逻辑如下:

复制代码

1 public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {2    TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();3    for (ConfigurationClass configClass : configurationModel) {4       loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);5    }6 }

复制代码

复制代码

 1 private void loadBeanDefinitionsForConfigurationClass( 2       ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) { 3      if (trackedConditionEvaluator.shouldSkip(configClass)) { 4       String beanName = configClass.getBeanName(); 5       if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) { 6          this.registry.removeBeanDefinition(beanName); 7       } 8       this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName()); 9       return;10    }11 12    if (configClass.isImported()) {13       registerBeanDefinitionForImportedConfigurationClass(configClass);14    }15   //将@Bean方法注册为bean16    for (BeanMethod beanMethod : configClass.getBeanMethods()) {17       loadBeanDefinitionsForBeanMethod(beanMethod);18    }19    //将configClass中中ImportResource指定的资源注册为bean20    loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());21 //将configClass中ImportedRegistrar注册为bean22    loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());23 }

复制代码

处理逻辑理了一遍后,看一下ConfigurationClassPostProcessor处理器解析@configuration配置类主要过程:

  1. Spring容器初始化时注册默认后置处理器ConfigurationClassPostProcessor

  2. Spring容器初始化执行refresh()方法中调用ConfigurationClassPostProcessor

  3. ConfigurationClassPostProcessor处理器借助ConfigurationClassParser完成配置类解析

  4. ConfigurationClassParser配置内解析过程中完成嵌套的MemberClass、@PropertySource注解、@ComponentScan注解(扫描package下的所有Class并进行迭代解析,主要是@Component组件解析及注册)、@ImportResource、@Bean等处理

  5. 完成@Bean注册, @ImportResource指定bean的注册以及@Import(实现ImportBeanDefinitionRegistrar接口方式)的bean注册

原文出处:https://www.cnblogs.com/ashleyboy/p/9667485.html  

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消