跳至主要內容

16、ConfigurationClassPostProcessor详细介绍

安图新大约 16 分钟

16、ConfigurationClassPostProcessor详细介绍

一,ConfigurationClassPostProcessor 简介

ConfigurationClassPostProcessor是一个后置处理器的类,主要功能是参与 BeanFactory 的建造,主要功能如下:

  • 解析加了@Configuration 的配置类
  • 解析@ComponentScan 扫描的包
  • 解析@ComponentScans 扫描的包
  • 解析@Import 注解

ConfigurationClassPostProcessor类图:

![ ][nbsp]

ConfigurationClassPostProcessor 实现了 BeanDefinitionRegistryPostProcessor 接口,而 BeanDefinitionRegistryPostProcessor 接口继承了 BeanFactoryPostProcessor 接口,所以 ConfigurationClassPostProcessor 中需要重写 postProcessBeanDefinitionRegistry() 方法和 postProcessBeanFactory() 方法。

  • postProcessBeanDefinitionRegistry()方法:定位、加载、解析、注册相关注解。
  • postProcessBeanFactory()方法:添加 CGLIB 增强处理及 ImportAwareBeanPostProcessor 后置处理类。

二,ConfigurationClassPostProcessor 注入时机

1,注解方式的注入

配置类SpringConfiguration.java

@Configuration
@ComponentScan(basePackages="com.bobo.aop.annotation")
@EnableAspectJAutoProxy
public class SpringConfiguration {

      }

启动类:

public class MyTest {


    public static void main(String[] args) {


        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);
    }
}

Spring 源码会在创建AnnotationConfigApplicationContext容器的时候,会去创建AnnotatedBeanDefinitionReader

	public AnnotationConfigApplicationContext(Class<?>... componentClasses) {


		this();
		register(componentClasses);
		refresh();
	}

	public AnnotationConfigApplicationContext() {


		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

在创建AnnotatedBeanDefinitionReader的过程中会去注入注解相关的后置处理器:

	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {


		this(registry, getOrCreateEnvironment(registry));
	}

	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {


		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		Assert.notNull(environment, "Environment must not be null");
		this.registry = registry;
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
        // 注入注解相关的后置处理器
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}

public abstract class AnnotationConfigUtils {


    public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {



		// 省略部分代码....

		// 创建BeanDefinitionHolder集合
		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

		// 注册内部管理的用于处理@configuration注解的后置处理器的bean
        // ConfigurationClassPostProcessor
		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {


			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		// 注册内部管理的用于处理@Autowired,@Value,@Inject以及@Lookup注解的后置处理器bean
        // AutowiredAnnotationBeanPostProcessor
		if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {


			RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		// 注册内部管理的用于处理JSR-250注解,例如@Resource,@PostConstruct,@PreDestroy的后置处理器bean
        // CommonAnnotationBeanPostProcessor
		if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {


			RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		// 注册内部管理的用于处理JPA注解的后置处理器bean
        // PersistenceAnnotationBeanPostProcessor
		if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {


			RootBeanDefinition def = new RootBeanDefinition();
			try {


				def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
						AnnotationConfigUtils.class.getClassLoader()));
			}
			catch (ClassNotFoundException ex) {


				throw new IllegalStateException(
						"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
			}
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		// 注册内部管理的用于处理@EventListener注解的后置处理器的bean
        // EventListenerMethodProcessor
		if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {


			RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
		}

		// 注册内部管理用于生产ApplicationListener对象的EventListenerFactory对象
        // DefaultEventListenerFactory
		if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {


			RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
		}

		return beanDefs;
	}
}

此处导入了五个后置处理器:

![ ][nbsp 1]

  • ConfigurationClassPostProcessor:beanName 为 internalConfigurationAnnotationProcessor 用于处理@configuration 注解的后置处理器的 bean
  • AutowiredAnnotationBeanPostProcessor:beanName 为 internalAutowiredAnnotationProcessor 用于处理@Autowired,@Value,@Inject 以及@Lookup 注解的后置处理器 bean
  • CommonAnnotationBeanPostProcessor:beanName 为 internalCommonAnnotationProcessor 用于处理 JSR-250 注解,例如@Resource,@PostConstruct,@PreDestroy 的后置处理器 bean
  • EventListenerMethodProcessor:beanName 为 internalEventListenerProcessor 用于处理@EventListener 注解的后置处理器的 bean
  • DefaultEventListenerFactory:beanName 为 internalEventListenerFactory 管理用于生产 ApplicationListener 对象的 EventListenerFactory 对象

2,XML 方式的注入

boboTest.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">
        <context:component-scan base-package="com.bobo.aop.annotation"/>
</beans>

测试类:

public class Test {



    public static void main(String[] args) {


        MyClassPathXmlApplicationContext ac = new MyClassPathXmlApplicationContext("boboTest.xml");
    }
}

源码中 document 树在解析 xml 文件的时候,解析到 context 标签属于自定义标签,所以会走自定义标签的解析

public class BeanDefinitionParserDelegate {


    public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {


		// 获取对应的命名空间
		String namespaceUri = getNamespaceURI(ele);
		if (namespaceUri == null) {


			return null;
		}
		// 根据命名空间找到对应的NamespaceHandlerspring
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler == null) {


			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}
		// 调用自定义的NamespaceHandler进行解析
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}
}

这里会获取到ComponentScanBeanDefinitionParser解析器,然后会走到 regsiterComponents()方法里面:

public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {


    protected void registerComponents(
			XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {



		// 省略部分代码....

		// Register annotation config processors, if necessary.
		boolean annotationConfig = true;
		if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {


			// 获取component-scan标签的annotation-config属性值,默认为true
			annotationConfig = Boolean.parseBoolean(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
		}
		if (annotationConfig) {


			// 如果annotation-config属性值为true,在给定的注册表中注册所有用于注解的bean后置处理器
			Set<BeanDefinitionHolder> processorDefinitions =
					AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
		}

		// 省略部分代码...
	}
}

可以看到获取到component-scan标签,默认会调用AnnotationConfigUtils.registerAnnotationConfigProcessors()方法,进行对注解相关的后置处理器的注册,此方法上面已经分析过了!

三,postProcessBeanDefinitionRegistry()方法

很显然 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()方法的执行是在 invokeBeanFactoryPostProcessors()方法中执行的,如果不了解 invokeBeanFactoryPostProcessors()方法的执行流程的话,请移步去看上一篇文章:吃透[Spring 源码(十五):invokeBeanFactoryPostProcessors 执行流程][Spring_invokeBeanFactoryPostProcessors]

此方法主要完成对@Configuration注解标注的BeanDefinition解析,同时解析出 @ComponentScan 和 @ComponentScans 扫描出的 Bean,也会解析出加了 @Bean 注解的方法所注册的 Bean,以及通过 @Import 注解注册的 Bean 和 @ImportResource 注解导入的配置文件中配置的 Bean。

下面我们直接到 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()方法中:

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
		PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {


     /**
	 * 定位、加载、解析、注册相关注解
	 */
	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {


		// 根据对应的registry对象生成hashcode值,此对象只会操作一次,如果之前处理过则抛出异常
		int registryId = System.identityHashCode(registry);

		// 将马上要进行处理的registry对象的id值放到已经处理的集合对象中
		this.registriesPostProcessed.add(registryId);

		// 处理配置类的bean定义信息
		processConfigBeanDefinitions(registry);
	}
}

处理配置类的 bean 定义信息方法:

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
		PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {


    /**
	 * 构建和验证一个类是否被@Configuration修饰,并做相关的解析工作
	 * 如果你对此方法了解清楚了,那么springboot的自动装配原理就清楚了
	 */
	public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {



        // 创建存放BeanDefinitionHolder的对象集合
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		// 当前registry就是DefaultListableBeanFactory,获取所有已经注册的BeanDefinition的beanName
		String[] candidateNames = registry.getBeanDefinitionNames();

        //----------------第一步-----------------
        // 遍历所有要处理的beanDefinition的名称,筛选对应的被注解修饰的beanDefinition
		for (String beanName : candidateNames) {


			// 获取指定名称的BeanDefinition对象
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);

			// 判断当前BeanDefinition是否是一个配置类,并为BeanDefinition设置属性为lite或者full,此处设置属性值是为了后续进行调用
			// 如果Configuration配置proxyBeanMethods代理为true则为full
			// 如果加了@Bean、@Component、@ComponentScan、@Import、@ImportResource注解,则设置为lite
			// 如果配置类上被@Order注解标注,则设置BeanDefinition的order属性值
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {


				// 添加到对应的集合对象中
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}


        //----------------第二步-----------------
        // 存放相关的BeanDefinitionHolder对象
		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		// 存放扫描包下的所有bean
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		do {


			// 解析带有@Controller、@Import、@ImportResource、@ComponentScan、@ComponentScans、@Bean的BeanDefinition
			parser.parse(candidates);
			// 将解析完的Configuration配置类进行校验,1、配置类不能是final,2、@Bean修饰的方法必须可以重写以支持CGLIB
			parser.validate();

			// 获取所有的bean,包括扫描的bean对象,@Import导入的bean对象
			Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
			// 清除掉已经解析处理过的配置类
			configClasses.removeAll(alreadyParsed);

			// Read the model and create bean definitions based on its content
			// 判断读取器是否为空,如果为空的话,就创建完全填充好的ConfigurationClass实例的读取器
			if (this.reader == null) {


				this.reader = new ConfigurationClassBeanDefinitionReader(
						registry, this.sourceExtractor, this.resourceLoader, this.environment,
						this.importBeanNameGenerator, parser.getImportRegistry());
			}


            //----------------第三步-----------------
			// 核心方法,将完全填充好的ConfigurationClass实例转化为BeanDefinition注册入IOC容器
			this.reader.loadBeanDefinitions(configClasses);
			// 添加到已经处理的集合中
			alreadyParsed.addAll(configClasses);

			candidates.clear();


            //----------------第四步-----------------
			// 这里判断registry.getBeanDefinitionCount() > candidateNames.length的目的是为了知道reader.loadBeanDefinitions(configClasses)这一步有没有向BeanDefinitionMap中添加新的BeanDefinition
			// 实际上就是看配置类(例如AppConfig类会向BeanDefinitionMap中添加bean)
			// 如果有,registry.getBeanDefinitionCount()就会大于candidateNames.length
			// 这样就需要再次遍历新加入的BeanDefinition,并判断这些bean是否已经被解析过了,如果未解析,需要重新进行解析
			// 这里的AppConfig类向容器中添加的bean,实际上在parser.parse()这一步已经全部被解析了
			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());
				}
				// 如果有未解析的类,则将其添加到candidates中,这样candidates不为空,就会进入到下一次的while的循环中
				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());
    }
}

1,第一步,筛选出被@Configuration 注解标注的 BeanDefinition

遍历容器中的BeanDefinitionNames集合,找出来被@Configuration标注的BeanDefinition并加入到代处理集合configCandidates中。

主要由ConfigurationClassUtils.checkConfigurationClassCandidate()方法来完成:

abstract class ConfigurationClassUtils {


    public static boolean checkConfigurationClassCandidate(
			BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {



		// 获取bean定义信息中的class类名
		String className = beanDef.getBeanClassName();

		AnnotationMetadata metadata;
		// 通过注解注入的db都是AnnotatedGenericBeanDefinition,实现了AnnotatedBeanDefinition
		// spring内部的bd是RootBeanDefinition,实现了AbstractBeanDefinition
		// 此处主要用于判断是否归属于AnnotatedBeanDefinition
		if (beanDef instanceof AnnotatedBeanDefinition &&
				className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {


			// Can reuse the pre-parsed metadata from the given BeanDefinition...
			// 从当前bean的定义信息中获取元数据信息
			metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
		}
		// 判断是否是spring中默认的BeanDefinition
		else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {


			Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
			// 如果class实例是下面四种类或接口的子类、父接口等任何一种情况,直接返回
			if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
					BeanPostProcessor.class.isAssignableFrom(beanClass) ||
					AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
					EventListenerFactory.class.isAssignableFrom(beanClass)) {


				return false;
			}
			// 为给定类创建新的AnnotationMetadata实例
			metadata = AnnotationMetadata.introspect(beanClass);
		}
		// 如果上述两种情况都不符合
		else {


			try {


				// 获取className的MetadataReader实例
				MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
				// 读取底层类的完整注释元数据,包括带注解方法的元数据
				metadata = metadataReader.getAnnotationMetadata();
			}
		}

		// 获取bean定义的元数据被@Configuration注解标注的属性字典值
		Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
		// 如果bean被@Configuration注解标注,且属性proxyBeanMethods为false(使用代理模式),则将bean定义记为full
		if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {


			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
		}
		// 如果bean被@configuration注解标注,且被注解@Component,@ComponentScan、@Import、@ImportResource或者@Bean标记的方法,则将bean定义标记为lite
		else if (config != null || isConfigurationCandidate(metadata)) {


			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
		}
		else {


			return false;
		}

		// bean定义是一个标记为full或lite的候选项,如果设置order则设置order属性值
		Integer order = getOrder(metadata);
		// 如果值不为空的话,那么直接设置值到具体的beanDefinition
		if (order != null) {


			// 设置bean定义的order值
			beanDef.setAttribute(ORDER_ATTRIBUTE, order);
		}

		return true;
	}
}

以上主要完成:

判断当前 BeanDefinition 是否被@Configuration 注解标注,如果是,并为 BeanDefinition 设置属性为 lite 或者 full,此处设置属性值是为了后续进行调用。如果不是被@Configuration 注解标注,直接返回 false。

如果被@Configuration 注解标注:

1、 配置 proxyBeanMethods 代理为 true 则为 full;
2、 如果又被标注了@Bean、@Component、@ComponentScan、@Import、@ImportResource 注解,则设置为 lite;
3、 如果配置类上被@Order 注解标注,则设置 BeanDefinition 的 order 属性值;
4、 返回 true,则该 beanDefinition 会被加入到 configCandidates 集合中;

执行完第一步,我们的例子中只有 SpringConfiguration 是被@Configuration 注解标注的,所以符合。

![ ][nbsp 2]

2,第二步,解析被@Configuration 注解标注的 BeanDefinition

解析被@Configuration 注解标注的 BeanDefinition 且带有@Controller、@Import、@ImportResource、@ComponentScan、@ComponentScans、@Bean 的 BeanDefinition,获取所有的 bean,包括扫描的 bean 对象,@Import 导入的 bean 对象等放入 configClasses 集合里面。

主要是由 ConfigurationClassParser#paser()方法来完成的

class ConfigurationClassParser {


    public void parse(Set<BeanDefinitionHolder> configCandidates) {


		// 循环遍历configCandidates
		for (BeanDefinitionHolder holder : configCandidates) {


			// 获取BeanDefinition
			BeanDefinition bd = holder.getBeanDefinition();
			// 根据BeanDefinition类型的不同,调用parse不同的重载方法,实际上最终都是调用processConfigurationClass()方法
			try {


				// 注解类型
				if (bd instanceof AnnotatedBeanDefinition) {


					parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
				}
				// 有class对象的
				else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {


					parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
				}
				else {


					parse(bd.getBeanClassName(), holder.getBeanName());
				}
			}
		}
	}


    protected void  processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {


		// 判断是否跳过解析,基于@Conditional标签判断该对象是否要跳过
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {


			return;
		}

		// SourceClass的意义:简单的包装类,目的是为了以统一的方式去处理带有注解的类,不管这些类是如何加载的
		SourceClass sourceClass = asSourceClass(configClass, filter);
		do {


			// 解析各种注解
			sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
		}
		while (sourceClass != null);

		// 将解析的配置类存储起来,这样回到parse方法时,能取到值
		this.configurationClasses.put(configClass, configClass);
	}


    protected final SourceClass doProcessConfigurationClass(
			ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
			throws IOException {


		// @Configuration继承了@Component
		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {


			// 递归处理内部类,因为内部类也是一个配置类,配置类上有@configuration注解,该注解继承@Component,if判断为true,调用processMemberClasses方法,递归解析配置类中的内部类
			processMemberClasses(configClass, sourceClass, filter);
		}

		// 如果配置类上加了@PropertySource注解,那么就解析加载properties文件,并将属性添加到spring上下文中
		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), PropertySources.class,
				org.springframework.context.annotation.PropertySource.class)) {


			if (this.environment instanceof ConfigurableEnvironment) {


				processPropertySource(propertySource);
			}
		}

		// 处理@ComponentScan或者@ComponentScans注解,并将扫描包下的所有bean转换成填充后的ConfigurationClass
		// 此处就是将自定义的bean加载到IOC容器,因为扫描到的类可能也添加了@ComponentScan和@ComponentScans注解,因此需要进行递归解析
		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) {


				// The config class is annotated with @ComponentScan -> perform the scan immediately
				// 解析@ComponentScan和@ComponentScans配置的扫描的包所包含的类
				// 比如 basePackages = com.bobo, 那么在这一步会扫描出这个包及子包下的class,然后将其解析成BeanDefinition
				// (BeanDefinition可以理解为等价于BeanDefinitionHolder)
				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				// 通过上一步扫描包com.bobo,有可能扫描出来的bean中可能也添加了ComponentScan或者ComponentScans注解.
				//所以这里需要循环遍历一次,进行递归(parse),继续解析,直到解析出的类上没有ComponentScan和ComponentScans
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {


					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {


						bdCand = holder.getBeanDefinition();
					}
					// 判断是否是一个配置类,并设置full或lite属性
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {


						// 通过递归方法进行解析
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}

		// 处理@Import注解
		processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

		// 处理@ImportResource注解,导入spring的配置文件
		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注解的方法,将@Bean方法转化为BeanMethod对象,保存再集合中
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {


			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		// 处理接口的默认方法实现,从jdk8开始,接口中的方法可以有自己的默认实现,因此如果这个接口的方法加了@Bean注解,也需要被解析
		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;
	}
}

3,第三步,将扫描到的所有 beanDefinition 注册到容器的 BeanDefinitionMap 中

将第二步中扫描到的所有 bean(在configClasses中存放着),注入到容器的BeanDefinitionMap中,完成导入 bean 的注入工作。

class ConfigurationClassBeanDefinitionReader {



    public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {


		TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
		for (ConfigurationClass configClass : configurationModel) {


			// 循环调用loadBeanDefinitionsForConfigurationClass方法
			loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
		}
	}

    /**
	 * 读取一个单独的ConfigurationClass类,注册bean本身(@Import引入的普通类)或者@Configuration配置类的Bean方法
	 */
	private void loadBeanDefinitionsForConfigurationClass(
			ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {



		// 如果一个bean是通过@Import(ImportSelector)的方式添加到容器中的,那么此时configClass.isImported()返回的是true
		// 而且configClass的importedBy属性里面存储的是ConfigurationClass就是将bean导入的类
		if (configClass.isImported()) {


			registerBeanDefinitionForImportedConfigurationClass(configClass);
		}
		// 判断当前的bean中是否含有@Bean注解的方法,如果有,需要把这些方法产生的bean放入到BeanDefinitionMap当中
		for (BeanMethod beanMethod : configClass.getBeanMethods()) {


			loadBeanDefinitionsForBeanMethod(beanMethod);
		}

		// 将@ImportResource引入的资源注入IOC容器
		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());

		// 如果bean上存在@Import注解,且import的是一个实现了ImportBeanDefinitionRegistrar接口,
        //则执行ImportBeanDefinitionRegistrar的registerBeanDefinitions()方法
        			      loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}
}

最终会注册到BeanDefinitionMap中。

4,第四步,判断第三步中注入到 BeanDefinitionMap 中 BeanDefinition 是否已经被解析过,如果没有被解析过,那么需要继续解析

			// 这里判断registry.getBeanDefinitionCount() > candidateNames.length的目的是为了知道reader.loadBeanDefinitions(configClasses)这一步有没有向BeanDefinitionMap中添加新的BeanDefinition
			// 如果有,registry.getBeanDefinitionCount()就会大于candidateNames.length
			// 这样就需要再次遍历新加入的BeanDefinition,并判断这些bean是否已经被解析过了,如果未解析,需要重新进行解析
			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());
				}
				// 如果有未解析的类,则将其添加到candidates中,这样candidates不为空,就会进入到下一次的while的循环中
				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;
			}

这里判断 registry.getBeanDefinitionCount() > candidateNames.length 的目的是为了知道 reader.loadBeanDefinitions(configClasses)这一步有没有向 BeanDefinitionMap 中添加新的 BeanDefinition,如果有,registry.getBeanDefinitionCount()就会大于 candidateNames.length,这样就需要再次遍历新加入的 BeanDefinition,并判断这些 bean 是否已经被解析过了,如果未解析,需要重新进行解析。

四,postProcessBeanFactory()方法

当然 ConfigurationClassPostProcessor#postProcessBeanFactory()方法的执行也是在 invokeBeanFactoryPostProcessors()方法中执行的,如果不了解 invokeBeanFactoryPostProcessors()方法的执行流程的话,请移步去看上一篇文章:吃透[Spring 源码(十五):invokeBeanFactoryPostProcessors 执行流程][Spring_invokeBeanFactoryPostProcessors]

此方法主要是对被@Configuration注解标注的类添加 CGLIB 增强处理以及添加ImportAwareBeanPostProcessor后置处理。

下面我们直接到 ConfigurationClassPostProcessor#postProcessBeanFactory()方法中:

	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {


		int factoryId = System.identityHashCode(beanFactory);

        // 如果还没执行解析工作,则先去执行processConfigBeanDefinitions进行解析
		this.factoriesPostProcessed.add(factoryId);
		if (!this.registriesPostProcessed.contains(factoryId)) {


			processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
		}
		// 对当前容器中被@Configuration注解标注的BeanDefinition进行CGLIb增强
		enhanceConfigurationClasses(beanFactory);
        // 添加ImportAwareBeanPostProcessor后置处理器
		beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
	}

为什么要对被@Configuration注解标注的类添加 CGLIB 增强?

解释这个问题我们先来看一段代码:

@Configuration
public class SpringConfiguration {


    @Bean
    public A a() {


        return new A();
    }

    @Bean
    public B b() {


        a();
        return new B();
    }
}

配置类中有两个方法,a()方法返回对象 A,b()方法调用一下 a()方法,在返回对象 B,并且都被@Bean 注解修饰。

SpringConfiguration 配置类,在被 Spring 容器去创建 B 对象的时候,此时 A 对象已经创建,那么调用 a()方法会再去创建 A 对象,所以无法保证 Bean 对象的单例性。

凡是加了@Configuration 注解修饰的类都会被 spring 代理,目的是为了解决@Bean 单例问题

五,总结

  • ConfigurationClassPostProcessor 类是用来对@Configuration 注解标注的 BeanDefinition 来处理的。
  • postProcessBeanDefinitionRegistry()方法是解析@Configuration 注解标注的 BeanDefinition,同时解析出 @ComponentScan 和 @ComponentScans 扫描出的 Bean,也会解析出加了 @Bean 注解的方法所注册的 Bean,以及通过 @Import 注解注册的 Bean 和 @ImportResource 注解导入的配置文件中配置的 Bean
  • postProcessBeanFactory()方法,对加了@Configuration 注解修饰的类都会被 spring 代理,目的是为了解决@Bean 单例问题。 [nbsp]: https://cdn.hotmindshare.com/custom/images/2024/2/22/134/1708578252490.png [nbsp 1]: https://cdn.hotmindshare.com/custom/images/2024/2/22/134/1708578252967.png [Spring_invokeBeanFactoryPostProcessors]: https://blog.csdn.net/u013277209/article/details/114594589 [nbsp 2]: https://cdn.hotmindshare.com/custom/images/2024/2/22/134/1708578253324.png