编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

深入理解Spring Cloud一(8)Bean是如何创建的(三)

wxchong 2024-08-16 06:10:37 开源技术 20 ℃ 0 评论

本文解析ConfigurationClassPostProcessor的源码,理解Bean注册到BeanFactory的过程。

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
   processConfigBeanDefinitions(registry);
}

一、解析Configuration类的整体流程

1.解析出有注解@Configuration的BeanDefinition

else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
   configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}

2.进行排序

// Sort by previously determined @Order value, if applicable
configCandidates.sort((bd1, bd2) -> {
   int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
   int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
   return Integer.compare(i1, i2);
});

3.创建ConfigurationClassParser

// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
      this.metadataReaderFactory, this.problemReporter, this.environment,
      this.resourceLoader, this.componentScanBeanNameGenerator, registry);

4.解析出ConfigurationClass

parser.parse(candidates);
parser.validate();

Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());

5.使用ConfigurationClassBeanDefinitionReader处理configClasses

if (this.reader == null) {
   this.reader = new ConfigurationClassBeanDefinitionReader(
         registry, this.sourceExtractor, this.resourceLoader, this.environment,
         this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);

6.检查BeanFactory中是否有新的未被解析的带有注解@Configuration的类,如果有继续上述解析操作。

if (registry.getBeanDefinitionCount() > candidateNames.length) {
   String[] newCandidateNames = registry.getBeanDefinitionNames();
   Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
   Set<String> alreadyParsedClasses = new HashSet<>();
   for (ConfigurationClass configurationClass : alreadyParsed) {
      alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
   }
   for (String candidateName : newCandidateNames) {
      if (!oldCandidateNames.contains(candidateName)) {
         BeanDefinition bd = registry.getBeanDefinition(candidateName);
         if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
               !alreadyParsedClasses.contains(bd.getBeanClassName())) {
            //有新的未被解析到的带有注解@Configuration的类
            candidates.add(new BeanDefinitionHolder(bd, candidateName));
         }
      }
   }
   candidateNames = newCandidateNames;
}

二、ConfigurationClassParser的解析过程

parser.parse(candidates);

我们以bootstrap的SpringApplication加载流程中解析BootstrapImportSelectorConfiguration来说明。

builder.sources(BootstrapImportSelectorConfiguration.class);


进入parse流程,开始对BootstrapImportSelectorConfiguration进行循环解析。


	protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;
		}
		// Recursively process the configuration class and its superclass hierarchy.
		SourceClass sourceClass = asSourceClass(configClass, filter);
		do {
			sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
		}
		while (sourceClass != null);

		this.configurationClasses.put(configClass, configClass);
	}


1.如果有@Component 注解,则解析member (nested) classes是否有@Component、@ComponentScan、@Import、@ImportResource注解,再查找是否有 @Bean methods。如果有符合上述条件的SourceClass则再次进入processConfigurationClass进行递归调用。

if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
   // Recursively process any member (nested) classes first
   processMemberClasses(configClass, sourceClass, filter);
}
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,
      Predicate<String> filter) throws IOException {

   Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
   if (!memberClasses.isEmpty()) {
      List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
      for (SourceClass memberClass : memberClasses) {
         if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
               !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
            candidates.add(memberClass);
         }
      }
      OrderComparator.sort(candidates);
      for (SourceClass candidate : candidates) {
         if (this.importStack.contains(configClass)) {
            this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
         }
         else {
            this.importStack.push(configClass);
            try {
               processConfigurationClass(candidate.asConfigClass(configClass), filter);
            }
            finally {
               this.importStack.pop();
            }
         }
      }
   }
}

2.解析@PropertySource注解,将加载的配置合并到environment中

// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
      sourceClass.getMetadata(), PropertySources.class,
      org.springframework.context.annotation.PropertySource.class)) {
   if (this.environment instanceof ConfigurableEnvironment) {
      processPropertySource(propertySource);
   }
}

3.解析@ComponentScans注解,将扫描的Bean注册到BeanFactory中,如果扫描到的Bean中有注解@Configuration的类,则进入parse进行解析。

if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
   parse(bdCand.getBeanClassName(), holder.getBeanName());
}

4.解析@Import注解

// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

5.解析注解@ImportResource

// Process any @ImportResource annotations
AnnotationAttributes importResource =
      AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
   String[] resources = importResource.getStringArray("locations");
   Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
   for (String resource : resources) {
      String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
      configClass.addImportedResource(resolvedResource, readerClass);
   }
}

6.解析sourceClass上有@Bean注解的方法

// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
   configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}

7.解析接口默认方法上有@Bean注解的方法

// Process default methods on interfaces
processInterfaces(configClass, sourceClass);

8.如果有父类,返回父类继续解析,否则代表处理结束

// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
   String superclass = sourceClass.getMetadata().getSuperClassName();
   if (superclass != null && !superclass.startsWith("java") &&
         !this.knownSuperclasses.containsKey(superclass)) {
      this.knownSuperclasses.put(superclass, configClass);
      // Superclass found, return its annotation metadata and recurse
      return sourceClass.getSuperClass();
   }
}

// No superclass -> processing is complete
return null;

三、总结

以注解了@Configuration的类为核心,抽象出ConfigurationClass对象,然后围绕着解析ConfigurationClass类上面是否有@Component 、@PropertySources、@ComponentScans、@Import、@ImportResource、@Bean methods、default @Bean methods on interfaces,最后再通过ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(configClasses),把所有的Bean注册到BeanFactory中。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表