东湖之滨 发表于 2023-6-7 18:59:25

Spring IOC @Configuration注解分析

引入

在使用SpringBoot开发时,最常用的注解有@Component、@Service、@Controller、@Configuration等。当类使用这些注解标记时,类会被Spring IOC容器管理,包括创建,填充属性和实例化。
但是Spring容器如何发现并将这些类放到容器进行管理呢?
今天这篇博客主要分析Spring如何处理@Configuration注解。
@Configuration定义

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
        @AliasFor(annotation = Component.class)
        String value() default "";
       
        //Since: 5.2
        boolean proxyBeanMethods() default true;

        //Since: 6.0
        boolean enforceUniqueMethods() default true;
}看Configuration注解的定义,它本质也是一个@Component注解。
所以,标记有@Configuration注解的类在Spring注册bean的第一阶段就会被注册到容器中,但是使用@Configuration注解的类内部的其他bean并没有被注册到容器中。
想知道@Configuration注解被如何处理,需要看invokeBeanFactoryPostProcessors 方法。
ConfigurationClassPostProcessor处理@Configuration注解

先大致说一下invokeBeanFactoryPostProcessors 方法的基本流程,因为这个方法会处理所有BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor接口的子类:

[*]先处理方法入参:beanFactoryPostProcessors(如果只是分析AnnotationConfigApplicationContext,这个参数是空的。只有在分析SpringBoot的启动过程时,这个参数才会有值)
[*]再处理BeanDefinitionRegistryPostProcessor的子类

[*]这里最重要的一件事情是调用ConfigurationClassPostProcessor的processConfigBeanDefinitions方法。

[*]最后处理BeanFactoryPostProcessor的子类
invokeBeanFactoryPostProcessors 的部分代码:
public static void invokeBeanFactoryPostProcessors(
                ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
       
        Set<String> processedBeans = new HashSet<>();
        if (beanFactory instanceof BeanDefinitionRegistry) {
                //省略部分代码,处理入参:beanFactoryPostProcessors

      //开始处理BeanDefinitionRegistryPostProcessor接口的子类
      //保存所有符合的子类,即实现BeanDefinitionRegistryPostProcessor,同样实现PriorityOrdered
                List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
                String[] postProcessorNames =
                                beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
                for (String ppName : postProcessorNames) {
                        if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                                processedBeans.add(ppName);
                        }
                }
                sortPostProcessors(currentRegistryProcessors, beanFactory);
                registryProcessors.addAll(currentRegistryProcessors);
      //调用currentRegistryProcessors中所有的BDRPP
                invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
                currentRegistryProcessors.clear();

                //省略部分代码,同样处理BeanDefinitionRegistryPostProcessor接口的子类
        }
        else {
                //省略部分代码
        }
        //省略部分代码 处理BeanFactoryPostProcessor接口的子类
}以上是invokeBeanFactoryPostProcessors的部分代码,接下来看ConfigurationClassPostProcessor的processConfigBeanDefinitions方法,在这个方法里开始正式地处理@Configruation注解:
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
        List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
        String[] candidateNames = registry.getBeanDefinitionNames();

        //遍历所有的候选者
        for (String beanName : candidateNames) {
                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);
                        }
                }
                //校验候选者类上是否使用了@Configuration注解
                else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
                        configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
                }
        }

        //如果configCandidates为空,则立即返回
        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);
        });

        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;
                        }
                }
        }

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

        // 创建一个解析@Configuration的解析器
        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 {
                StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
                //开始解析候选类
                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());
                }

                //注册解析后的类到容器中
                this.reader.loadBeanDefinitions(configClasses);

                alreadyParsed.addAll(configClasses);
                processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
                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());
        // 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();
        }

}这个方法的关键点:

[*]找到所有要解析的类
[*]创建一个解析者
[*]开始解析类

[*]记住,这里只是解析,也就是确认所有需要处理的类或者方法,这些类或者方法最终也会注册到容器中

[*]注册解析后的类到容器中:this.reader.loadBeanDefinitions(configClasses);
解析

那么实际上如何解析呢?
protected final SourceClass doProcessConfigurationClass(
                ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
                throws IOException {
        //1. 判断当前类是否有内部类,如果有内部类是否使用了@Configuration注解,如果使用了该注解,那么需要先处理内部类的配置
        //存在这种可能,但是实际开发中很少使用
        if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
                processMemberClasses(configClass, sourceClass, filter);
        }

        // 处理@PropertySource注解
        for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
                        sourceClass.getMetadata(), PropertySources.class,
                        org.springframework.context.annotation.PropertySource.class)) {
                if (this.environment instanceof ConfigurableEnvironment) {
                        processPropertySource(propertySource);
                }
                else {
                        logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                                        "]. Reason: Environment must implement ConfigurableEnvironment");
                }
        }

        // 处理@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) {
                        Set<BeanDefinitionHolder> scannedBeanDefinitions =
                                        this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
                        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), filter, true);

        // 处理@ImportResource注解
        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));
        }
        // Process default methods on interfaces
        processInterfaces(configClass, sourceClass);
        // Process superclass, if any
        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();
                }
        }
        // No superclass -> processing is complete
        return null;
}processImports方法主要处理两种情况:

[*]实现ImportSelector接口的类
[*]实现ImportBeanDefinitionRegistrar接口的类
但是需要注意,这个方法只是把这些类放到了集合中,但是还没有开始处理。
下面开始看如何处理使用@Bean的方法
@Configuration
@Import(MyBeanFactoryPostProcessor.class)
public class JavaConfig {
    @Bean
    public Country country() {
      return new Country();
    }
}最后返回所有需要处理的方法。
注册

public class MyBeanFactoryPostProcessor implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
      ImportBeanDefinitionRegistrar.super.registerBeanDefinitions(importingClassMetadata, registry, importBeanNameGenerator);
      RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
      rootBeanDefinition.setBeanClass(Person.class);

      registry.registerBeanDefinition("person", rootBeanDefinition);
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
      ImportBeanDefinitionRegistrar.super.registerBeanDefinitions(importingClassMetadata, registry);
    }
}
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: Spring IOC @Configuration注解分析