Spring中的ConfigurationClassPostProcessor

ConfigurationClassPostProcessor是Spring Framework中的一个bean工厂后置处理器,而且还是一个registry后置处理器,Spring Framework和Spring Boot中的很多功能都是由该类来实现的,可以说该类十分强大。本文就来分析一下该类都做了哪些操作,以及是怎么做的。


registry后置操作

java
spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java
@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);
}

主要的实现在processConfigBeanDefinitions方法中。

processConfigBeanDefinitions
candidateIndicators
<
>
java
spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    // 获取bean工厂中的所有bean
    String[] candidateNames = registry.getBeanDefinitionNames();

    /*
     * 遍历每一个bean
     */
    for (String beanName : candidateNames) {
        // 获取bean定义
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
        if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
            if (logger.isDebugEnabled()) {
                logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
            }
        }
        /*
         * 判断beanDef对应的class是否被@Configuration修饰,如果是并判断和设置配置的模式(full还是lite)
         * 如果被@Configuration注解修饰,那么proxyTargetClass属性为true的话则是full模式,否则是lite模式
         * 如果不是被@Configuration修饰(只能是lite模式),
         * 	那么再判断是否是其他情况,参考ConfigurationClassUtils#isConfigurationCandidate()方法。
         * 所以这里可以看出,不是只有@Configuration的才是配置类。
         */
        else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
            // 如果满足配置类的要求,那么加入到候选者集合中
            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
    // 对配置类根据@Order进行排序
    configCandidates.sort((bd1, bd2) -> {
        int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
        int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
        return Integer.compare(i1, i2);
    });

    // 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) {
            // 如果不存在beanNameGenerator,则加载默认的
            BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
                    AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
            if (generator != null) {
                this.componentScanBeanNameGenerator = generator;
                this.importBeanNameGenerator = generator;
            }
        }
    }

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

    // Parse each @Configuration class
    // 创建解析配置类的解析器
    ConfigurationClassParser parser = new ConfigurationClassParser(
            this.metadataReaderFactory, this.problemReporter, this.environment,
            this.resourceLoader, this.componentScanBeanNameGenerator, registry);

    // 表示每次循环需要处理的配置类
    Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
    // 记录已经解析过的的配置类,也就是执行过this.reader.loadBeanDefinitions方法的bean。
    Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
    do {
        StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
        /*
         * 核心处理逻辑
         * 会解析其内部的注解,包括@PropertySource、@ComponentScan、@Import、@ImportResource、@Bean
         * 每个被@Configuration修饰的类都会生成一个ConfigurationClass
         */
        parser.parse(candidates);
        /*
         * 校验配置类
         * 如类不能被final修饰,@Bean标注的方法不能被private修饰
         */
        parser.validate();

        // 获取所有生成的ConfigurationClass,包含了之前处理过的,所以下面要移除掉
        Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
        // 移除掉已经被处理过的配置类
        configClasses.removeAll(alreadyParsed);

        // Read the model and create bean definitions based on its content
        /*
         * 创建ConfigurationClassBeanDefinitionReader对象,用于扫描出ConfigurationClass中的BeanDefinition
         */
        if (this.reader == null) {
            this.reader = new ConfigurationClassBeanDefinitionReader(
                    registry, this.sourceExtractor, this.resourceLoader, this.environment,
                    this.importBeanNameGenerator, parser.getImportRegistry());
        }
        /*
         * 加载ConfigurationClass中的beanDefinition并注册,主要有以下来源:
         * @Import导入对象,该注解可导入下面四种类:(这一点好像有问题)
         * 	1、被@Configuration修饰的类;
         * 	2、实现了ImportSelector接口的类;
         * 	3、实现了ImportBeanDefinitionRegistrar接口的类;
         * 	4、其他普通component类
         * @Configuration修饰的类中被@Bean注解修饰的方法
         * @ImportSource注解导入的资源中配置的类
         *
         *
         */
        this.reader.loadBeanDefinitions(configClasses);
        // 添加到已经解析过的列表中,避免后续重复解析
        alreadyParsed.addAll(configClasses);
        processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();

        // 清空列表,准备下一轮循环
        candidates.clear();
        // 前后数量不等,说明确实load到了bean
        if (registry.getBeanDefinitionCount() > candidateNames.length) {
            // 获取bean工厂中的所有bean的名称
            String[] newCandidateNames = registry.getBeanDefinitionNames();
            // 本次循环前的bean名称集合
            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) {
                // 第一次筛选:筛选出本次do...while循环新加载到的bean,即不在旧列表中的bean
                if (!oldCandidateNames.contains(candidateName)) {
                    BeanDefinition bd = registry.getBeanDefinition(candidateName);
                    /*
                     * 第二次筛选:
                     * 如果又新加载进来了配置类,且不是之前已经处理过的(其实循环开头也是会remove掉已经处理过的配置类),
                     * 那么将其加入到candidates再次循环处理
                     */
                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                            !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                        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 && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
        sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
    }

    if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
        // Clear cache in externally provided MetadataReaderFactory; this is a no-op
        // for a shared cache since it'll be cleared by the ApplicationContext.
        ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
    }
}
java
spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassUtils.java
private static final Set<String> candidateIndicators = new HashSet<>(8);

// 如果类上面有下面四种注解,那么会认为该类是配置类
static {
    candidateIndicators.add(Component.class.getName());
    candidateIndicators.add(ComponentScan.class.getName());
    candidateIndicators.add(Import.class.getName());
    candidateIndicators.add(ImportResource.class.getName());
}
	public static boolean checkConfigurationClassCandidate(
			BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {

		String className = beanDef.getBeanClassName();
		// 存在factory-method的情况不算是配置类
		if (className == null || beanDef.getFactoryMethodName() != null) {
			return false;
		}

		// 获取目标类的元数据
		AnnotationMetadata metadata;
		// 可以直接获取元数据的情况
		if (beanDef instanceof AnnotatedBeanDefinition &&
				className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
			// Can reuse the pre-parsed metadata from the given BeanDefinition...
			// 直接获取元数据
			metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
		}
		else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
			// Check already loaded Class if present...
			// since we possibly can't even load the class file for this Class.
			Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
			// 如果类属于下面几种,则不属于是配置类
			if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
					BeanPostProcessor.class.isAssignableFrom(beanClass) ||
					AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
					EventListenerFactory.class.isAssignableFrom(beanClass)) {
				return false;
			}
			// 根据Class来构建元数据
			metadata = AnnotationMetadata.introspect(beanClass);
		}
		else {
			try {
				// 获取元数据读取器
				MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
				// 读取元数据
				metadata = metadataReader.getAnnotationMetadata();
			}
			catch (IOException ex) {
				if (logger.isDebugEnabled()) {
					logger.debug("Could not find class file for introspecting configuration annotations: " +
							className, ex);
				}
				return false;
			}
		}

		// 如果存在@Configuration注解,那么获取注解内的proxyBeanMethods属性,并据此设置配置的模式(full还是lite)
		Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
		// 如果存在@Configuration注解,且proxyBeanMethods属性为true,那么是FULL模式
		if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
		}
		// 如果没有@Configuration注解,但是类满足几点要求也算是配置类(具体是什么要求点进去看),不过是LITE模式
		else if (config != null || isConfigurationCandidate(metadata)) {
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
		}
		else {
			return false;
		}

		// It's a full or lite configuration candidate... Let's determine the order value, if any.
		// 获取配置类的顺序,也就是类上@Order注解的value值
		Integer order = getOrder(metadata);
		if (order != null) {
			// 设置顺序
			beanDef.setAttribute(ORDER_ATTRIBUTE, order);
		}

		return true;
	}

这个方法非常长,但逻辑还是很清楚的。 首先获取当前bean工厂中的所有配置类,然后以该获取结果作为遍历的起点,在do...while循环中调用ConfigurationClassParserConfigurationClassBeanDefinitionReader来处理。前者主要是扫描配置类中的bean和其他配置类,后者主要是注册扫描到的bean。如果加载到有bean,那么筛选出新加载到的配置类,然后以此作为遍历对象再次循环处理。这个过程属于广度优先遍历(BFS)。 其实核心的实现在那两个类里面,请参考:

普通后置操作

java
spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    int factoryId = System.identityHashCode(beanFactory);
    // 判断是否已经处理过这个bean工厂了
    if (this.factoriesPostProcessed.contains(factoryId)) {
        throw new IllegalStateException(
                "postProcessBeanFactory already called on this post-processor against " + beanFactory);
    }
    this.factoriesPostProcessed.add(factoryId);
    // 判断有没有处理过配置类,其实在上面的postProcessBeanDefinitionRegistry方法中就已经处理过了,所以这里可以忽略
    if (!this.registriesPostProcessed.contains(factoryId)) {
        // BeanDefinitionRegistryPostProcessor hook apparently not supported...
        // Simply call processConfigurationClasses lazily at this point then.

        // 处理配置bean的定义
        processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
    }

    // CGLIB提升
    enhanceConfigurationClasses(beanFactory);
    // 注册bean后置处理器
    beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

主要的实现都在enhanceConfigurationClasses这个方法中。

java
spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
    StartupStep enhanceConfigClasses = this.applicationStartup.start("spring.context.config-classes.enhance");
    Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
    // 遍历所有的bean名称
    for (String beanName : beanFactory.getBeanDefinitionNames()) {
        // 获取bean定义
        BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
        /*
         * 获取配置类的属性,该属性是在ConfigurationClassUtils的checkConfigurationClassCandidate方法中设置的,
         * 有full和lite两种值。
         */
        Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
        AnnotationMetadata annotationMetadata = null;
        MethodMetadata methodMetadata = null;
        // 获取元数据
        if (beanDef instanceof AnnotatedBeanDefinition) {
            AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDef;
            annotationMetadata = annotatedBeanDefinition.getMetadata();
            methodMetadata = annotatedBeanDefinition.getFactoryMethodMetadata();
        }
        if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
            // Configuration class (full or lite) or a configuration-derived @Bean method
            // -> eagerly resolve bean class at this point, unless it's a 'lite' configuration
            // or component class without @Bean methods.
            AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
            // 如果bean的class不是属于java.lang.Class的子类型
            if (!abd.hasBeanClass()) {
                boolean liteConfigurationCandidateWithoutBeanMethods =
                        // 如果是lite模式
                        (ConfigurationClassUtils.CONFIGURATION_CLASS_LITE.equals(configClassAttr) &&
                            annotationMetadata != null &&
                                // 不含有bean方法
                                !ConfigurationClassUtils.hasBeanMethods(annotationMetadata));

                // 不是lite模式,或者含有bean方法
                if (!liteConfigurationCandidateWithoutBeanMethods) {
                    try {
                        // 解析bean的class
                        abd.resolveBeanClass(this.beanClassLoader);
                    }
                    catch (Throwable ex) {
                        throw new IllegalStateException(
                                "Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
                    }
                }
            }
        }
        // 如果是full模式
        if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
            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)) {
            }
            // 将bean定义添加到集合中,便于下面统一处理
            configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
        }
    }
    // 没有需要进行CGLIB提升的配置类,则直接返回
    if (configBeanDefs.isEmpty() || NativeDetector.inNativeImage()) {
        // nothing to enhance -> return immediately
        enhanceConfigClasses.end();
        return;
    }

    ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
    // 遍历属于full模式的配置bean的定义
    for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
        // 获取bean定义
        AbstractBeanDefinition beanDef = entry.getValue();
        // If a @Configuration class gets proxied, always proxy the target class
        beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
        // Set enhanced subclass of the user-specified bean class
        // 获取配置类的Class对象
        Class<?> configClass = beanDef.getBeanClass();
        // 通过CGLIB创建一个配置类的子类
        Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
        if (configClass != enhancedClass) {
            // 替换bean定义中的bean的类为CGLIB创建的子类
            beanDef.setBeanClass(enhancedClass);
        }
    }
    enhanceConfigClasses.tag("classCount", () -> String.valueOf(configBeanDefs.keySet().size())).end();
}

这个方法筛选了所有模式为full的配置bean,什么样才算是full模式呢,具体参考上面给出的checkConfigurationClassCandidate方法的代码,在其尾部判断了类是否被@Configuration注解所修饰,且proxyBeanMethods属性是否是true,如果都是则认为是full模式,否则是lite模式。 然后对所有的full模式的配置类,利用CGLIB来生成代理类。full模式的配置类中的bean方法多次调用返回的是同一个对象,就是因为这里进行代理增强。

总结

本文分析了ConfigurationClassPostProcessor,可以说该类是官方提供的最重要和最强大的一个BeanFactoryPostProcessor都不为过,在该类中实现了大量Spring框架提供的功能。核心实现单独抽离到了单独的两篇文章中,这样显得本文的主题更为清晰。