Configuration注解ConfigurationClassPostProcessor运行原理

本文解释了在Spring框架中,如何识别带有@Configuration注解的类以及其@Bean方法作为配置类,同时介绍了配置类的处理过程,包括元数据解析、代理和BeanDefinition的生成。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/**
 * <pre>
 *
 *  new AnnotationConfigApplicationContext(AppConfigDemo.class, ComponentE.class);
 * 总结: AppConfigDemo,ComponentE都会作为Bean来对待,什么情况下会作为配置类来对待呢?
 *      1. 类上存在@Configuration,@Component,@ComponentScan,@Import,@ImportResource
 *      2. 如果不存在上面的注解,那么类中存在@Bean的方法也是作为一个配置类对待
 *      3. 其他情况,它就是一个不同的@Bean
 *
 * </pre>
 */
class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        int registryId = System.identityHashCode(registry);
        this.registriesPostProcessed.add(registryId);
        // 处理配置类的BeanDefinition
        processConfigBeanDefinitions(registry) {
            // 配置类的BD
            List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
            // 容器中所有的Bean的Name
            String[] candidateNames = registry.getBeanDefinitionNames();
            // 遍历所有beanName
            for (String beanName : candidateNames) {
                // 获取BD
                BeanDefinition beanDef = registry.getBeanDefinition(beanName);
                // 校验当前Bean是否符合配置类的条件
                if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory) {
                    String className = beanDef.getBeanClassName();
                    // 如果没有类名,获取是@Bean方法,则不符合条件
                    if (className == null || beanDef.getFactoryMethodName() != null) {
                        return false;
                    }
                    // 如果类名相同,元数据相同,可以重用
                    AnnotationMetadata metadata;
                    if (beanDef instanceof AnnotatedBeanDefinition && className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
                        metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
                    }
                    // 如果类型不相同,并且设置了Bean的Class
                    else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
                        // 获取Bean的class
                        Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
                        // 如果这个类又是BeanFactoryPostProcessor,BeanPostProcessor下面几种类型就不处理
                        // 不符合配置类的条件
                        if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
                                BeanPostProcessor.class.isAssignableFrom(beanClass) ||
                                AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
                                EventListenerFactory.class.isAssignableFrom(beanClass)) {
                            return false;
                        }
                        // 创建当前类的元数据对象
                        metadata = AnnotationMetadata.introspect(beanClass) {
                            return new StandardAnnotationMetadata(introspectedClass, true);
                        }
                    }
                    // 其他条件,如果没有设置Bean的class,那么BD中存入的是类的全类名字符串
                    else {
                        // 获取元数据读取的工厂,根据类名解析该类的元数据
                        MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
                        // 解析该类的元数据
                        metadata = metadataReader.getAnnotationMetadata();
                    }
                    // 以上的if就是获取类的元数据,说白了就是解析类的信息,例如类名,注解,等等信息

                    // 获取注解Configuration中的所有属性信息
                    Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
                    // 如果存在表示有这个注解
                    // 获取proxyBeanMethods的值,如果是默认值true的话,表示@Bean方法需要被代理,因为@Bean的方法可以直接调用多次,返回的是同一个对象
                    // 所以必须要代理才能做到,如果是这种情况,则标记该类是个重量级的类
                    if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
                        beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
                    }
                    // 如果存在Configuration注解proxyBeanMethods为false的话,表示@Bean方法调用多次可以返回不同的对象,则无需代理
                    // 或者
                    else if (config != null || isConfigurationCandidate(metadata) {
                        // 如果此类是接口,不处理
                        if (metadata.isInterface()) {
                            return false;
                        }

                        // static {
                        // 	candidateIndicators.add(Component.class.getName());
                        // 	candidateIndicators.add(ComponentScan.class.getName());
                        // 	candidateIndicators.add(Import.class.getName());
                        // 	candidateIndicators.add(ImportResource.class.getName());
                        // }
                        // 如果是类上存在上面这几个注解,表示也属于配置Bean,也算作是一个配置类
                        for (String indicator : candidateIndicators) {
                            if (metadata.isAnnotated(indicator)) {
                                return true;
                            }
                        }

                        // 上面几种都没,判断当前类中是否存在@Bean标注的方法,如果存在,也表示是一个配置类
                        return metadata.hasAnnotatedMethods(Bean.class.getName());
                    }){
                        // 这种情况,标记当前类为轻量级的配置类
                        beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
                    }
                    // 不存在标注为Bean的注解
                    else{
                        return false;
                    }
                    // 获取类上的Order注解
                    Integer order = getOrder(metadata) {
                        // 获取Order注解的属性
                        Map<String, Object> orderAttributes = metadata.getAnnotationAttributes(Order.class.getName());
                        return (orderAttributes != null ? ((Integer) orderAttributes.get(AnnotationUtils.VALUE)) : null);
                    }
                    // 如何存在Order注解,设置该Bean的Order值
                    if (order != null) {
                        beanDef.setAttribute(ORDER_ATTRIBUTE, order);
                    }
                    // 符合条件,不符合条件的上面已经返回false了
                    return true;
                }){
                    // 保存该类为一个配置类
                    configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
                }
            }

            // 如果没有找到@Configuration类,立即返回
            if (configCandidates.isEmpty()) {
                return;
            }

            // 根据@Order注解的顺序进行排序解析
            configCandidates.sort((bd1, bd2) -> {
                int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
                int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
                return Integer.compare(i1, i2);
            });
            // 是否使用本地的BeanName生成器,也就是有没有指定的BeanNameGenerator
            // localBeanNameGeneratorSet默认为false
            if (!this.localBeanNameGeneratorSet) {
                // 从容器中获取BeanNameGenerator
                BeanNameGenerator generator = (BeanNameGenerator) registry.getSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
                // 如果获取到了
                if (generator != null) {
                    // 设置@ComponentScan扫描的类使用该BeanNameGenerator
                    this.componentScanBeanNameGenerator = generator;
                    // 设置@Import的类使用该BeanNameGenerator
                    this.importBeanNameGenerator = generator;
                }
            }
            // 上下文环境对象
            if (this.environment == null) {
                this.environment = new StandardEnvironment();
            }

            // 创建Config类的解析器
            ConfigurationClassParser parser = new ConfigurationClassParser(
                    // 用于解析类元数据的工厂
                    this.metadataReaderFactory,
                    // 解析时出现的问题报告
                    this.problemReporter,
                    // 环境对俩
                    this.environment,
                    // 加载类资源器
                    this.resourceLoader,
                    // 用于@ComponentScan扫描的类使用的BeanName生成器
                    this.componentScanBeanNameGenerator,
                    // Bean容器
                    registry);
            // 符合条件的Bean
            Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
            // 解析解析过的配置类
            Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
            do {
                // 解析配置类,详见Spring中ConfigClass配置类是如何解析的
                parser.parse(candidates);
                // 校验解析的configClass,比如final的方法,静态方法,还有重写的方法,或者私有方法,抽象方法
                parser.validate();
                // 获取解析到的所有的配置类,封装成ConfigurationClass对象
                Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
                // 删除已经解析过了的ConfigurationClass
                configClasses.removeAll(alreadyParsed);
                // 创建BeanDefinitionReader,它是将配置类中的配置统一进行成BeanDefinition的类
                // 例如@Bean方法,@Import注解,说白了扫描的类都是由它来生成BeanDefinition
                if (this.reader == null) {
                    this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry());
                }
                // 解析所有的配置属性,这个时候,BD就已经解析好了,详见BeanDefinitionReader的工作原理
                this.reader.loadBeanDefinitions(configClasses);
                // 保存已经解析的配置类
                alreadyParsed.addAll(configClasses);
                // 清空所有的配置类,因为都已经被解析过了
                candidates.clear();
                // 容器中现在存在的Bean与解析之前存在的@Bean的数量是不是发生了变化
                // 如果大于,表示解析出来了新的Bean
                // 那么我们就要对新解析的Bean进行再次解析
                if (registry.getBeanDefinitionCount() > candidateNames.length) {
                    // 获取最新的所有的BeanName
                    String[] newCandidateNames = registry.getBeanDefinitionNames();
                    // 原始的所有BeanName
                    Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
                    // 保存已经解析过的类
                    Set<String> alreadyParsedClasses = new HashSet<>();
                    // 遍历所有已经解析过的配置类
                    for (ConfigurationClass configurationClass : alreadyParsed) {
                        // 保存起来
                        alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
                    }
                    // 遍历最新的所有BeanName
                    for (String candidateName : newCandidateNames) {
                        // 如果新解析出来的Bean没有被解析过
                        if (!oldCandidateNames.contains(candidateName)) {
                            // 获取BD
                            BeanDefinition bd = registry.getBeanDefinition(candidateName);
                            // 校验当前Bean是否符合配置类的条件,上面有这个方法的详解,并且该类没有被解析过
                            if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) && !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                                // 保存新的需要解析的配置类
                                candidates.add(new BeanDefinitionHolder(bd, candidateName));
                            }
                        }
                    }
                    // 将这次最新的BeanName保存到candidateNames变量中
                    // candidateNames始终保存了上一次解析的所有BeanName
                    candidateNames = newCandidateNames;
                }
            }
            // 当不断解析出来了新的Bean,那么就要一直解析,知道没有解析出新的Bean为止
            while (!candidates.isEmpty());

            // 如果不包含IMPORT_REGISTRY_BEAN_NAME,注入这个单例Bean
            // 这个类是给解析@Import注解使用的,它保存了@Import导入的类
            if (registry != null && !registry.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
                registry.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
            }
            // 清空解析的类的一些元数据的缓存
            if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
                ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
            }
        }
    }

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 在postProcessBeanDefinitionRegistry会执行processConfigBeanDefinitions
        // 如果postProcessBeanDefinitionRegistry没有被执行,就需要执行一次
        // 总之processConfigBeanDefinitions一定会被执行一次,用来解析所有配置类
        if (!this.registriesPostProcessed.contains(factoryId)) {
            processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
        }
        // 给ConfigurationClass创建代理对象,因为@Bean方法的方法调用返回的是相同的Bean,所以需要给这个Config进行代理
        enhanceConfigurationClasses(beanFactory){
            // 配置类的BD
            Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
            // 遍历所有的Bean
            for (String beanName : beanFactory.getBeanDefinitionNames()) {
                // 获取BD
                BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
                // 获取代理类的标识
                Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
                MethodMetadata methodMetadata = null;
                if (beanDef instanceof AnnotatedBeanDefinition) {
                    // 获取方法的元数据
                    methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
                }
                if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
                    AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
                    // 不存在Class,表示存入的是类全名,将类全名解析为Class
                    if (!abd.hasBeanClass()) {
                        abd.resolveBeanClass(this.beanClassLoader);
                    }
                }
                // 如果该配置类设置了当前类是重量级类,表示需要使用代理完成@Bean方法多次调用返回同一个对象
                // 并且,只有在@Configuration类中,才会设置为CONFIGURATION_CLASS_FULL
                // 在@Component中是不会的,所以@Conmponent中的@Bean方法,每次调用都是返回一个新对象
                if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
                    // 保存需要代理的配置类
                    configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
                }
            }
            // 如果没有解析到配置类,就不处理
            if (configBeanDefs.isEmpty()) {
                return;
            }
            // 创建CGLIB生成器
            ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
            // 遍历所有的需要代理的配置类BD
            for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
                AbstractBeanDefinition beanDef = entry.getValue();
                // 如果@Configuration需要被代理,默认使用CGLIB代理
                beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
                // 获取Class类
                Class<?> configClass = beanDef.getBeanClass();
                // 生成ConfigClass的代理Class
                Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
                if (configClass != enhancedClass) {
                    // 使用代理的BeanClass代替原来的Class
                    beanDef.setBeanClass(enhancedClass);
                }
            }
        }
        // 添加一个处理实现了ImportAware导入的后置处理器,会将导入的配置类的元数据给它
        // 所以,如果我们需要拿到导入的某一个类的元数据,就可以实现这个接口
        beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值