Spring BeanDefinitionRegistryPostProcessor : ConfigurationClassPostProcessor

概述

ConfigurationClassPostProcessor 位于 org.springframework.context.annotation 包中,这是一个 BeanDefinitionRegistryPostProcessor,隐含地也实现了接口BeanFactoryPostProcessor,用于 spring 应用启动过程中 @Configuration 类的处理 : 发现和处理所有的配置类,注册其中的bean定义。

继承关系

在这里插入图片描述

关于应用

1. 何时被引入

  1. SpringbootSping应用,当在配置文件中使用<context:annotation-config/>或者 <context:component-scan/>时,该BeanFactoryPostProcessor会被注册。

  2. Springboot 应用中在ApplicationContext对象创建时,会在应用上下文类(参考AnnotationConfigServletWebServerApplicationContext/AnnotationConfigReactiveWebServerApplicationContext)的构造函数中创建AnnotatedBeanDefinitionReader对象时调用 AnnotationConfigUtils.registerAnnotationConfigProcessors() 注册这个BeanFactoryPostProcessor到容器。

// AnnotationConfigUtils#registerAnnotationConfigProcessors 代码片段

		// 这里 CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME 值为 :
		// org.springframework.context.annotation.internalConfigurationAnnotationProcessor
		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));
		}		

2. 何时被使用

ConfigurationClassPostProcessor既实现了BeanDefinitionRegistryPostProcessor定义的方法postProcessBeanDefinitionRegistry,也实现了接口BeanFactoryPostProcessor定义的方法postProcessBeanFactory

AbstractApplicationContext.refresh()方法执行时,在BeanFactory,也就是Spring容器被准备(prepare)和postProcess之后,AbstractApplicationContextinvokeBeanFactoryPostProcessors()方法被调用,这个方法用来执行所有容器中被作为bean注册的BeanFactoryPostProcessor,其中就包括对ConfigurationClassPostProcessor方法postProcessBeanDefinitionRegistry()以及postProcessBeanFactory()方法的调用。

 // 调用链 
 AbstractApplicationContext.refresh()
	=> invokeBeanFactoryPostProcessors()
 	=> PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()

PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()方法会先应用所有的BeanDefinitionRegistryPostProcessor的方法postProcessBeanDefinitionRegistry(),直到参数指定的或者容器中所有的这些BeanDefinitionRegistryPostProcessor的该方法都被执行完,然后执行所有的BeanFactoryPostProcessor的方法postProcessBeanFactory()直到参数指定的或者容器中所有的这些BeanFactoryPostProcessor的该方法都被执行完。

这里之所有这样做的原因是上述方法执行时有可能注册新的BeanDefinitionRegistryPostProcessor/BeanFactoryPostProcessor到容器,而这些新注册的BeanDefinitionRegistryPostProcessor/BeanFactoryPostProcessor也需要在这个阶段执行。

另外需要注意 :

  1. BeanDefinitionRegistryPostProcessor可能会注册另外一个BeanDefinitionRegistryPostProcessor

  2. 一个非BeanDefinitionRegistryPostProcessor BeanFactoryPostProcessor可能会注册另外一个BeanFactoryPostProcessor

  3. 一个非BeanDefinitionRegistryPostProcessor BeanFactoryPostProcessor不会注册另外一个BeanDefinitionRegistryPostProcessor(注册了但是不会被执行)。

因为配置类中定义的每个bean定义方法都必须要赶在其它BeanFactoryPostProcessor应用前,所以完成bean定义注册任务的ConfigurationClassPostProcessor 被设计为拥有最高执行优先级Ordered.HIGHEST_PRECEDENCE

源代码分析

1.postProcessBeanDefinitionRegistry()

使用工具ConfigurationClassParser尝试发现所有的配置(@Configuration)类,使用工具ConfigurationClassBeanDefinitionReader注册所发现的配置类中所有的bean定义。结束执行的条件是所有配置类都被发现和处理,相应的bean定义注册到容器。

	/**
	 * Derive further bean definitions from the configuration classes in the registry.
	 */
	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
		int registryId = System.identityHashCode(registry);
		if (this.registriesPostProcessed.contains(registryId)) {
			throw new IllegalStateException(
					"postProcessBeanDefinitionRegistry already 	" + 
					"called on this post-processor against " + registry);
		}
		if (this.factoriesPostProcessed.contains(registryId)) {
			throw new IllegalStateException(
					"postProcessBeanFactory already called on this post-processor against " 
					+ registry);
		}
		this.registriesPostProcessed.add(registryId);

		processConfigBeanDefinitions(registry);
	}
	
   /**
     * Build and validate a configuration model based on the registry of
     * Configuration classes.
     */
    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
        // 用来记录候选配置类
        List<BeanDefinitionHolder> configCandidates = new ArrayList<BeanDefinitionHolder>();
        // 将容器中已经登记的Bean定义作为候选配置类名称 , 举例如下 :
        // candidateNames = {String[8]@3533} 
        //  0 = "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"
        //  1 = "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"
        //  2 = "org.springframework.context.annotation.internalCommonAnnotationProcessor"
        //  3 = "org.springframework.context.annotation.internalPersistenceAnnotationProcessor"
        //  4 = "org.springframework.context.event.internalEventListenerProcessor"
        //  5 = "org.springframework.context.event.internalEventListenerFactory"
        //  6 = "application" ⇐ 这是开发人员使用了注解 @SpringBootApplication 的程序入口类
        //  7 = "org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory"        
        String[] candidateNames = registry.getBeanDefinitionNames();
        // 程序此时处于容器启动的早期, 通常此时 candidateNames 中实际上只会有一个配置类,
        // 在上例中就是 application

        for (String beanName : candidateNames) {
            BeanDefinition beanDef = registry.getBeanDefinition(beanName);
            if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                    ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Bean definition has already been processed "+ 
                    "as a configuration class: " + beanDef);
                }
            }
            else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,
            	 this.metadataReaderFactory)) {
                // 如果这个Bean定义有注解@Configuration,将其记录为候选配置类
                configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
            }
        }

        // Return immediately if no @Configuration classes were found
        if (configCandidates.isEmpty()) {
            // 一个候选配置类都没有找到,直接返回
            return;
        }

        // Sort by previously determined @Order value, if applicable
        Collections.sort(configCandidates, new Comparator<BeanDefinitionHolder>() {
            @Override
            public int compare(BeanDefinitionHolder bd1, BeanDefinitionHolder bd2) {
                int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
                int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
                return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
            }
        });

        // Detect any custom bean name generation strategy supplied through the 
        // enclosing application context
        SingletonBeanRegistry sbr = null;
        if (registry instanceof SingletonBeanRegistry) {
            sbr = (SingletonBeanRegistry) registry;
            if (!this.localBeanNameGeneratorSet && 
            	sbr.containsSingleton(CONFIGURATION_BEAN_NAME_GENERATOR)) {
                BeanNameGenerator generator = (BeanNameGenerator) 
                	sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
                this.componentScanBeanNameGenerator = generator;
                this.importBeanNameGenerator = generator;
            }
        }

        // Parse each @Configuration class,现在准备要分析配置类了
        ConfigurationClassParser parser = new ConfigurationClassParser(
                this.metadataReaderFactory, this.problemReporter, this.environment,
                this.resourceLoader, this.componentScanBeanNameGenerator, registry);

        // 表示将要被处理的候选配置类
        // 因为不清楚候选是否确实是配置类,所以使用BeanDefinitionHolder类型记录
        // 这里初始化为方法开始时容器中注解了@Configuration的Bean定义的集合
        Set<BeanDefinitionHolder> candidates = 
        	new LinkedHashSet<BeanDefinitionHolder>(configCandidates);
        // 表示已经处理的配置类,已经被处理的配置类已经明确了其类型,所以用 ConfigurationClass 类型记录,
        // 这里初始化为空
        Set<ConfigurationClass> alreadyParsed = 
        	new HashSet<ConfigurationClass>(configCandidates.size());
        do {
            // 分析配置类,分析过程中
            // 1. 如果遇到注解了@Component类,直接作为Bean定义注册到容器
            // 2. 如果注解或者注解的注解中有@Import, 处理所有这些@import,识别配置类,
            //    添加到分析器的属性configurationClasses中去
            parser.parse(candidates);
            parser.validate();

            // 从分析器parser中获取分析得到的配置类configurationClasses
            Set<ConfigurationClass> configClasses = 
            	new LinkedHashSet<ConfigurationClass>(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());
            }
            // 使用 ConfigurationClassBeanDefinitionReader reader 从 configClasses 中加载
            // Bean定义并注册到容器
            this.reader.loadBeanDefinitions(configClasses);
            // 刚刚处理完的配置类记录到已处理配置类alreadyParsed
            alreadyParsed.addAll(configClasses);

            // 清空候选配置类集合,为下一轮do循环做初始化准备
            candidates.clear();
            if (registry.getBeanDefinitionCount() > candidateNames.length) {
                // 经过一轮do循环,现在容器中Bean定义数量超过了该次循环开始时的容器内Bean定义数量,
                // 说明在该次循环中发现并注册了更多的Bean定义到容器中去,这些新注册的Bean定义
                // 也有可能是候选配置类,它们也要被处理用来发现和注册Bean定义
                String[] newCandidateNames = registry.getBeanDefinitionNames();
                Set<String> oldCandidateNames = 
                	new HashSet<String>(Arrays.asList(candidateNames));
                Set<String> alreadyParsedClasses = new HashSet<String>();
                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())) {
                                // 在新注册的Bean定义中找到一个候选配置类
                            candidates.add(new BeanDefinitionHolder(bd, candidateName));
                        }
                    }
                }
                candidateNames = newCandidateNames;
            }
        }
        while (!candidates.isEmpty());// 一直循环到没有新的候选配置类被发现

        // Register the ImportRegistry as a bean in order to support ImportAware 
        // @Configuration classes
        if (sbr != null) {
            if (!sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
                sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
            }
        }

        if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
            ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
        }
    }

2. postProcessBeanFactory()

postProcessBeanFactory() 的主要目的有两个:

  1. 对容器中的每个配置类做增强;
  2. 往容器中增加一个BeanPostProcessor:ImportAwareBeanPostProcessor(如果所增加的BeanPostProcessor已经存在会先将其删除然后重新添加)
	/**
	 * Prepare the Configuration classes for servicing bean requests at runtime
	 * by replacing them with CGLIB-enhanced subclasses.
	 */
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		int factoryId = System.identityHashCode(beanFactory);
		if (this.factoriesPostProcessed.contains(factoryId)) {
			throw new IllegalStateException(
					"postProcessBeanFactory already called on this post-processor against " + beanFactory);
		}
		this.factoriesPostProcessed.add(factoryId);
		if (!this.registriesPostProcessed.contains(factoryId)) {
			// 因为同一个ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry
			// 总是先于它的postProcessBeanFactory被调用,因此代码应该不会执行到这里,所以这里再次调用
			// 应该是一次确保
			// BeanDefinitionRegistryPostProcessor hook apparently not supported...
			// Simply call processConfigurationClasses lazily at this point then.
			processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
		}

		//  对容器中的每个配置类做增强
		enhanceConfigurationClasses(beanFactory);
		// 往容器中增加一个ImportAwareBeanPostProcessor(如果所增加组件已经存在会先将其删除然后重新添加)
		beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
	}

2.1 使用ConfigurationClassEnhancer增强每个配置类

	public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
		// 从容器中找到所有配置类的bean定义
		Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
		for (String beanName : beanFactory.getBeanDefinitionNames()) {
			BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
			if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
				if (!(beanDef instanceof AbstractBeanDefinition)) {
					throw new BeanDefinitionStoreException(
			"Cannot enhance @Configuration bean definition '" +
			beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
				}
				else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
			logger.info("Cannot enhance @Configuration bean definition '" 
			+ beanName +
			"' since its singleton instance has been created too early. The typical cause " +
			"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
			"return type: Consider declaring such methods as 'static'.");
				}
				configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
			}
		}
		if (configBeanDefs.isEmpty()) {
			// nothing to enhance -> return immediately
			return;
		}

		// 对每个配置类进行增强
		ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
		for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
			AbstractBeanDefinition beanDef = entry.getValue();
			// If a @Configuration class gets proxied, always proxy the target class
			beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
			try {
				// Set enhanced subclass of the user-specified bean class
				Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
				if (configClass != null) {
					Class<?> enhancedClass = enhancer.enhance(configClass, 
						this.beanClassLoader);
					if (configClass != enhancedClass) {
						if (logger.isTraceEnabled()) {
							logger.trace(
					String.format("Replacing bean definition '%s' existing class '%s' with " +
					"enhanced class '%s'", entry.getKey(), configClass.getName(), 
					enhancedClass.getName()));
						}
						beanDef.setBeanClass(enhancedClass);
					}
				}
			}
			catch (Throwable ex) {
				throw new IllegalStateException(
				"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
			}
		}
	}

2.2 添加ImportAwareBeanPostProcessor到容器

beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));

相关资料

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值