Spring源码分析之@Configuration注解的处理(Processing of @ configuration annotation in spring source code analysis)

前言

Spring从3.0开始支持JavaConfig配置,具体来说就是可以完全通过注解来开启Bean扫描,声明Bean,导入properties文件等。
主要有以下注解:
@Configuration: 标识此Bean是一个配置类,接下来开始解析此类
@ComponentScan: 开启注解扫描,默认扫描@Component注解
@Import: 导入其他配置类
@ImportResource: 导入其他XML配置文件
@Bean: 在方法上使用,声明此方法为一个Bean

简单使用

import java.util.ArrayList;
import java.util.LinkedList;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

public class TestConfiguration {

  public static void main(String[] args) {
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    BeanDefinitionBuilder builder = BeanDefinitionBuilder
        .genericBeanDefinition(BeanConfig.class);
    //注册BeanConfig类
    beanFactory.registerBeanDefinition("beanConfig", builder.getBeanDefinition());
    //处理@Configuration注解
    ConfigurationClassPostProcessor configurationClassPostProcessor = new ConfigurationClassPostProcessor();
    configurationClassPostProcessor.postProcessBeanDefinitionRegistry(beanFactory);
    configurationClassPostProcessor.postProcessBeanFactory(beanFactory);
    System.out.println(beanFactory.getBean("beanConfig").getClass());
    System.out.println(beanFactory.getBean("myArrayList").getClass());
    System.out.println(beanFactory.getBean(LinkedList.class).getClass());
  }

  @Configuration(proxyBeanMethods = true)
  @ComponentScan
  @Import({MyBeanRegistrar.class, MySelector.class})
  public static class BeanConfig {

  }

  public static class MyBeanRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
        BeanDefinitionRegistry registry) {
      BeanDefinitionBuilder builder = BeanDefinitionBuilder
          .genericBeanDefinition(ArrayList.class);
      registry.registerBeanDefinition("myArrayList", builder.getBeanDefinition());
    }
  }

  public static class MySelector implements ImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
      return new String[]{LinkedList.class.getName()};
    }
  }
}

这里为了更好的分析原理,没有使用更加强大的ApplicationContext,核心类为ConfigurationClassPostProcessor,
这是一个BeanDefinitionRegistryPostProcessor(BeanDefinitionRegistry后置处理器,可以让对BeanDefinitionRegistry进行扩展处理,如添加自定义的BeanDefinition),
也是一个BeanFactoryPostProcessor(BeanFactory后置处理器,可以让我们扩展BeanFactory)。
ConfigurationClassPostProcessor会判断Bean是否为一个配置类,如果是,就解析此类,具体就是解析@ComponentScan,@Import等注解。
如果我们使用支持JavaConfig的ApplicationContext,它会通过AnnotationConfigUtils的registerAnnotationConfigProcessors()方法来自动添加ConfigurationClassPostProcessor类。
ApplicationContext会在refresh()方法执行过程中处理ConfigurationClassPostProcessor的后置方法,
关于ApplicationContext,可以查看Spring源码分析之ApplicationContext 。

源码分析

在Spring源码分析之ApplicationContext 的基础上,我们可以知道,在refresh()方法的步骤invokeBeanFactoryPostProcessors()中,
会执行BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法,
然后再执行BeanFactoryPostProcessor的postProcessBeanFactory()方法,所以我们先分析ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry()方法。

postProcessBeanDefinitionRegistry

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	        //处理配置
		processConfigBeanDefinitions(registry);
	}

继续跟进去

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		String[] candidateNames = registry.getBeanDefinitionNames();
                //过滤出所有Bean中为配置类的Bean,下面会说判断的条件
		for (String beanName : candidateNames) {
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
			}
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}

		//没有配置类
		if (configCandidates.isEmpty()) {
			return;
		}

		//按照优先级排序
		configCandidates.sort((bd1, bd2) -> {
			int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
			int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
			return Integer.compare(i1, i2);
		});

		//从容器中查找Bean名称生成器
		SingletonBeanRegistry sbr = null;
		if (registry instanceof SingletonBeanRegistry) {
			sbr = (SingletonBeanRegistry) registry;
			if (!this.localBeanNameGeneratorSet) {
				BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
						AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
				if (generator != null) {
					this.componentScanBeanNameGenerator = generator;
					this.importBeanNameGenerator = generator;
				}
			}
		}

                //创建environment 
		if (this.environment == null) {
			this.environment = new StandardEnvironment();
		}

		//配置类解析器
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);

		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		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());
			}
                        //从解析好的配置类中加载BeanDefinition,注册到容器中
			this.reader.loadBeanDefinitions(configClasses);
			alreadyParsed.addAll(configClasses);

			candidates.clear();
                        //如果解析配置类的过程中,又导入了其他配置类,继续解析
			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())) {
							candidates.add(new BeanDefinitionHolder(bd, candidateName));
						}
					}
				}
				candidateNames = newCandidateNames;
			}
		}
		while (!candidates.isEmpty());

		//将ImportRegistry注册为一个Bean,用来支持ImportAware钩子回调
		if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
			sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
		}
	}

判断一个Bean为配置类的逻辑为

  • 判断Class是否包含@Configuration注解,如果包含,为配置类
  • 如果没有,@Component,@ComponentScan,@Import,@ImportResource,查看是否包含此4个注解之一,如果包含,为配置类
  • 如果没有,判断Class是否有方法包含@Bean注解

上述逻辑汇总,核心地方有两个,一个是解析配置类,一个是加载配置类,先看解析,进入ConfigurationClassParser解析器

public void parse(Set<BeanDefinitionHolder> configCandidates) {
		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
                                //根据不同的BeanDefinition类型调用不同的方法,最后解析时会统一处理
				if (bd instanceof AnnotatedBeanDefinition) {
					parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
				}
				else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
					parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
				}
				else {
					parse(bd.getBeanClassName(), holder.getBeanName());
				}
			}
		}
                //这个处理也是很重要的,延迟导入,SpringBoot提供的AutoConfigurationImportSelector就是一个延迟加载的导入选择器,
                //它会在我们我们自己的配置类加载之后再加载,相当于低优先级,
                //因为在处理OnMissingBeanCondition等注解时需要依赖前面的配置类来判断某个Bean是否已经在容器中存在
		this.deferredImportSelectorHandler.process();
	}

不同的BeanDefinition类型,都会统一创建一个ConfigurationClass来处理,继续跟进去

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
                //处理@Conditional注解,根据条件判断该配置类是否需要被加载
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;
		}

                //处理已经解析过的情况
		ConfigurationClass existingClass = this.configurationClasses.get(configClass);
		if (existingClass != null) {
			if (configClass.isImported()) {
				if (existingClass.isImported()) {
					existingClass.mergeImportedBy(configClass);
				}
				return;
			}
			else {
				this.configurationClasses.remove(configClass);
				this.knownSuperclasses.values().removeIf(configClass::equals);
			}
		}

		//递归处理配置类及父类
		SourceClass sourceClass = asSourceClass(configClass);
		do {
                        //核心,解析配置类
			sourceClass = doProcessConfigurationClass(configClass, sourceClass);
		}
		while (sourceClass != null);

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

开始真正的处理解析配置类

@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {

		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			//处理内部类的情况
			processMemberClasses(configClass, sourceClass);
		}

		//解析@PropertySource注解,用来处理properties文件,添加到environment中
		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), PropertySources.class,
				org.springframework.context.annotation.PropertySource.class)) {
			if (this.environment instanceof ConfigurableEnvironment) {
				processPropertySource(propertySource);
			}
		}

		//解析@ComponentScan注解
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
			for (AnnotationAttributes componentScan : componentScans) {
				//内部使用ClassPathBeanDefinitionScanner扫描器,默认扫描@Component注解,注意,扫描完成已经将BeanDefinition注册到容器中了
				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				//如果扫描到的BeanDefinition也包含配置类,递归解析配置类
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
                                        //判断是否为配置类
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}

		//解析@Import注解
		processImports(configClass, sourceClass, getImports(sourceClass), true);

		//解析@ImportResource注解,可以导入XML配置文件
		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);
			}
		}

		//解析包含@Bean注解的方法
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		//处理接口相关,不用管
		processInterfaces(configClass, sourceClass);

		//处理父类
		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();
			}
		}

		//没有父类,处理结束
		return null;
	}

关于解析@Import注解,此注解配置的类型可以有三种:

  • ImportSelector接口类型,可以看做一个导入选择器,返回多个要导入的Class类型,如SpringBoot自动装配的实现AutoConfigurationImportSelector。
  • ImportBeanDefinitionRegistrar,可以看做一个注册器,Spring提供的一个钩子,可以让我们向BeanDefinitionRegistry中添加自定义的BeanDefinition,
    如开启AOP的AspectJAutoProxyRegistrar。
  • 其他类型的配置类

接下来继续分析配置类的加载,进入ConfigurationClassBeanDefinitionReader的loadBeanDefinitions()方法

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
                //使用一个支持追踪的条件解析器来判断配置类是否可以加载,如果A配置类是被B配置类通过@Import注解引入的,B配置类不加载,那么A配置类也不能被加载
		TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
		for (ConfigurationClass configClass : configurationModel) {
                        //依次加载每一个配置类
			loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
		}
	}

继续

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);
		}
                //注册所有包含@Bean注解的方法到容器中,这种Bean通过工厂方法来实例化
		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}
                //使用XmlBeanDefinitionReader从XML配置文件中加载所有Bean,其实还支持groovy类型的配置文件,用的不多,就先不管了
		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
                //从注册器加载,依次调用所有ImportBeanDefinitionRegistrar的registerBeanDefinitions()方法
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}

至此Spring已经将所有的BeanDefinition都注册到容器中了。

postProcessBeanFactory

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		//使用CGLIB对配置类创建动态代理
		enhanceConfigurationClasses(beanFactory);
		beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
	}

通过来标记开启代理,默认就是true,主要是为了处理下面这种情况

@Configuration(proxyBeanMethods = true)
@Configuration(proxyBeanMethods = true)
public static class BeanConfig {
    @Bean("myHashSet")
    public Set<String> myHashSet() {
      return new HashSet<>();
    }
    @Bean("myArrayList")
    public List<String> myArrayList() {
      return new ArrayList<>(myHashSet());
    }
    @Bean("myLinkedList")
    public List<String> myLinkedList() {
      return new LinkedList<>(myHashSet());
    }
  }

在配置类中声明了3个Bean,按理来说只会创建一个名称为myHashSet的Bean,但myArrayList()和myLinkedList方法内部都调用了myHashSet()方法,不能创建两个myHashSet的Bean,
这就是因为Spring对配置类创建了动态代理对象,当调用myHashSet()方法时,会根据方法找到对应的Bean名称,从容器中查询出对应的Bean对象。

分析总结

Spring处理配置主要有以下几个类:

  • ConfigurationClassPostProcessor: 框架类,使用下面的几个类来完成解析,加载
  • ConfigurationClassParser: 解析所有配置类
  • ConfigurationClassBeanDefinitionReader: 加载所有配置类
  • ConfigurationClassEnhancer: 根据需要对配置类创建代理

Spring框架的核心有两个:

  • 注册BeanDefinition到容器中
    从各种渠道注册,如XML配置文件,@Component注解,@Bean注解,手动创建BeanDefinition注册,各种扩展类如ImportBeanDefinitionRegistrar的注册。
  • 根据BeanDefinition创建Bean对象
    创建过程中,可能会创建代理对象,这就是AOP的功能。

Spring很多附加的功能都是通过帮我们自动注册了很多BeanDefinition来完成的。

————————

preface

Spring has supported javaconfig configuration since 3.0. Specifically, it can start bean scanning, declare beans, import properties files, etc. through annotations.
There are mainly the following notes:
@Configuration: identify that this bean is a configuration class. Next, start parsing this class
@Componentscan: enables annotation scanning. The @ Component annotation is scanned by default
@Import: import other configuration classes
@Importresource: import other XML configuration files
@Bean: used on a method, declaring this method as a bean

Simple use

import java.util.ArrayList;
import java.util.LinkedList;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

public class TestConfiguration {

  public static void main(String[] args) {
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    BeanDefinitionBuilder builder = BeanDefinitionBuilder
        .genericBeanDefinition(BeanConfig.class);
    //注册BeanConfig类
    beanFactory.registerBeanDefinition("beanConfig", builder.getBeanDefinition());
    //处理@Configuration注解
    ConfigurationClassPostProcessor configurationClassPostProcessor = new ConfigurationClassPostProcessor();
    configurationClassPostProcessor.postProcessBeanDefinitionRegistry(beanFactory);
    configurationClassPostProcessor.postProcessBeanFactory(beanFactory);
    System.out.println(beanFactory.getBean("beanConfig").getClass());
    System.out.println(beanFactory.getBean("myArrayList").getClass());
    System.out.println(beanFactory.getBean(LinkedList.class).getClass());
  }

  @Configuration(proxyBeanMethods = true)
  @ComponentScan
  @Import({MyBeanRegistrar.class, MySelector.class})
  public static class BeanConfig {

  }

  public static class MyBeanRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
        BeanDefinitionRegistry registry) {
      BeanDefinitionBuilder builder = BeanDefinitionBuilder
          .genericBeanDefinition(ArrayList.class);
      registry.registerBeanDefinition("myArrayList", builder.getBeanDefinition());
    }
  }

  public static class MySelector implements ImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
      return new String[]{LinkedList.class.getName()};
    }
  }
}

In order to better analyze the principle, a more powerful ApplicationContext is not used. The core class is configurationclasspostprocessor,
This is a beandefinitionregistrypostprocessor (beandefinitionregistry postprocessor, which allows you to extend beandefinitionregistry, such as adding custom beandefinition),
It is also a beanfactory postprocessor (beanfactory postprocessor, which allows us to extend beanfactory).
Configurationclasspostprocessor will judge whether the bean is a configuration class. If so, resolve this class, specifically @ componentscan, @ import and other annotations.
If we use an ApplicationContext that supports javaconfig, it will automatically add the configurationclasspostprocessor class through the registerannotationconfigprocessors() method of annotationconfigutils.
ApplicationContext will process the post method of configurationclasspostprocessor during the execution of refresh() method,
For ApplicationContext, you can view the ApplicationContext of spring source code analysis.

Source code analysis

在Spring源码分析之ApplicationContext 的基础上,我们可以知道,在refresh()方法的步骤invokeBeanFactoryPostProcessors()中,
会执行BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法,
然后再执行BeanFactoryPostProcessor的postProcessBeanFactory()方法,所以我们先分析ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry()方法。

postProcessBeanDefinitionRegistry

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	        //处理配置
		processConfigBeanDefinitions(registry);
	}

Keep following

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		String[] candidateNames = registry.getBeanDefinitionNames();
                //过滤出所有Bean中为配置类的Bean,下面会说判断的条件
		for (String beanName : candidateNames) {
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
			}
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}

		//没有配置类
		if (configCandidates.isEmpty()) {
			return;
		}

		//按照优先级排序
		configCandidates.sort((bd1, bd2) -> {
			int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
			int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
			return Integer.compare(i1, i2);
		});

		//从容器中查找Bean名称生成器
		SingletonBeanRegistry sbr = null;
		if (registry instanceof SingletonBeanRegistry) {
			sbr = (SingletonBeanRegistry) registry;
			if (!this.localBeanNameGeneratorSet) {
				BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
						AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
				if (generator != null) {
					this.componentScanBeanNameGenerator = generator;
					this.importBeanNameGenerator = generator;
				}
			}
		}

                //创建environment 
		if (this.environment == null) {
			this.environment = new StandardEnvironment();
		}

		//配置类解析器
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);

		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		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());
			}
                        //从解析好的配置类中加载BeanDefinition,注册到容器中
			this.reader.loadBeanDefinitions(configClasses);
			alreadyParsed.addAll(configClasses);

			candidates.clear();
                        //如果解析配置类的过程中,又导入了其他配置类,继续解析
			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())) {
							candidates.add(new BeanDefinitionHolder(bd, candidateName));
						}
					}
				}
				candidateNames = newCandidateNames;
			}
		}
		while (!candidates.isEmpty());

		//将ImportRegistry注册为一个Bean,用来支持ImportAware钩子回调
		if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
			sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
		}
	}

The logic of judging a bean as a configuration class is

  • Judge whether the class contains @ configuration annotation. If so, it is a configuration class
  • 如果没有,@Component,@ComponentScan,@Import,@ImportResource,查看是否包含此4个注解之一,如果包含,为配置类
  • If not, judge whether the class contains @ bean annotation

In the above logical summary, there are two core places: one is to parse the configuration class, and the other is to load the configuration class. First look at the parsing and enter the configurationclassparser parser

public void parse(Set<BeanDefinitionHolder> configCandidates) {
		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
                                //根据不同的BeanDefinition类型调用不同的方法,最后解析时会统一处理
				if (bd instanceof AnnotatedBeanDefinition) {
					parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
				}
				else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
					parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
				}
				else {
					parse(bd.getBeanClassName(), holder.getBeanName());
				}
			}
		}
                //这个处理也是很重要的,延迟导入,SpringBoot提供的AutoConfigurationImportSelector就是一个延迟加载的导入选择器,
                //它会在我们我们自己的配置类加载之后再加载,相当于低优先级,
                //因为在处理OnMissingBeanCondition等注解时需要依赖前面的配置类来判断某个Bean是否已经在容器中存在
		this.deferredImportSelectorHandler.process();
	}

For different beandefinition types, a configurationclass will be created to handle them and continue to follow

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
                //处理@Conditional注解,根据条件判断该配置类是否需要被加载
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;
		}

                //处理已经解析过的情况
		ConfigurationClass existingClass = this.configurationClasses.get(configClass);
		if (existingClass != null) {
			if (configClass.isImported()) {
				if (existingClass.isImported()) {
					existingClass.mergeImportedBy(configClass);
				}
				return;
			}
			else {
				this.configurationClasses.remove(configClass);
				this.knownSuperclasses.values().removeIf(configClass::equals);
			}
		}

		//递归处理配置类及父类
		SourceClass sourceClass = asSourceClass(configClass);
		do {
                        //核心,解析配置类
			sourceClass = doProcessConfigurationClass(configClass, sourceClass);
		}
		while (sourceClass != null);

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

Start the real process of parsing the configuration class

@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {

		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			//处理内部类的情况
			processMemberClasses(configClass, sourceClass);
		}

		//解析@PropertySource注解,用来处理properties文件,添加到environment中
		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), PropertySources.class,
				org.springframework.context.annotation.PropertySource.class)) {
			if (this.environment instanceof ConfigurableEnvironment) {
				processPropertySource(propertySource);
			}
		}

		//解析@ComponentScan注解
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
			for (AnnotationAttributes componentScan : componentScans) {
				//内部使用ClassPathBeanDefinitionScanner扫描器,默认扫描@Component注解,注意,扫描完成已经将BeanDefinition注册到容器中了
				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				//如果扫描到的BeanDefinition也包含配置类,递归解析配置类
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
                                        //判断是否为配置类
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}

		//解析@Import注解
		processImports(configClass, sourceClass, getImports(sourceClass), true);

		//解析@ImportResource注解,可以导入XML配置文件
		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);
			}
		}

		//解析包含@Bean注解的方法
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		//处理接口相关,不用管
		processInterfaces(configClass, sourceClass);

		//处理父类
		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();
			}
		}

		//没有父类,处理结束
		return null;
	}

For parsing @ import annotation, there are three types of annotation configuration:

  • ImportSelector接口类型,可以看做一个导入选择器,返回多个要导入的Class类型,如SpringBoot自动装配的实现AutoConfigurationImportSelector。
  • ImportBeanDefinitionRegistrar,可以看做一个注册器,Spring提供的一个钩子,可以让我们向BeanDefinitionRegistry中添加自定义的BeanDefinition,
    如开启AOP的AspectJAutoProxyRegistrar。
  • Other types of configuration classes

Next, continue to analyze the loading of configuration classes and enter the loadbeandefinitions () method of configurationclassbeandefinitionreader

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
                //使用一个支持追踪的条件解析器来判断配置类是否可以加载,如果A配置类是被B配置类通过@Import注解引入的,B配置类不加载,那么A配置类也不能被加载
		TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
		for (ConfigurationClass configClass : configurationModel) {
                        //依次加载每一个配置类
			loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
		}
	}

continue

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);
		}
                //注册所有包含@Bean注解的方法到容器中,这种Bean通过工厂方法来实例化
		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}
                //使用XmlBeanDefinitionReader从XML配置文件中加载所有Bean,其实还支持groovy类型的配置文件,用的不多,就先不管了
		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
                //从注册器加载,依次调用所有ImportBeanDefinitionRegistrar的registerBeanDefinitions()方法
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}

So far, spring has registered all beandefinitions in the container.

postProcessBeanFactory

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		//使用CGLIB对配置类创建动态代理
		enhanceConfigurationClasses(beanFactory);
		beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
	}

Start the proxy by marking. The default is true. This is mainly to deal with the following situations

@Configuration(proxyBeanMethods = true)
@Configuration(proxyBeanMethods = true)
public static class BeanConfig {
    @Bean("myHashSet")
    public Set<String> myHashSet() {
      return new HashSet<>();
    }
    @Bean("myArrayList")
    public List<String> myArrayList() {
      return new ArrayList<>(myHashSet());
    }
    @Bean("myLinkedList")
    public List<String> myLinkedList() {
      return new LinkedList<>(myHashSet());
    }
  }

Three beans are declared in the configuration class. Normally, only one bean named myhashset will be created. However, myhashset () method is called inside myarraylist() and mylinkedlist methods, and two beans of myhashset cannot be created,
This is because spring creates a dynamic proxy object for the configuration class. When calling the myhashset () method, it will find the corresponding bean name according to the method and query the corresponding bean object from the container.

Analysis and summary

Spring processing configuration mainly includes the following classes:

  • ConfigurationClassPostProcessor: 框架类,使用下面的几个类来完成解析,加载
  • ConfigurationClassParser: 解析所有配置类
  • ConfigurationClassBeanDefinitionReader: 加载所有配置类
  • ConfigurationClassEnhancer: 根据需要对配置类创建代理

The core of spring framework has two aspects:

  • 注册BeanDefinition到容器中
    从各种渠道注册,如XML配置文件,@Component注解,@Bean注解,手动创建BeanDefinition注册,各种扩展类如ImportBeanDefinitionRegistrar的注册。
  • Create a bean object based on the beandefinition
    During the creation process, proxy objects may be created, which is the function of AOP.

Many additional functions of spring are completed by automatically registering many beandefinitions for us.