0


Spring IOC - ConfigurationClassPostProcessor源码解析

       上文提到Spring在Bean扫描过程中,会手动将5个Processor类注册到beanDefinitionMap中,其中ConfigurationClassPostProcessor就是本文将要讲解的内容,该类会在refresh()方法中通过调用invokeBeanFactoryPosstProcessors(beanFactory)被调用。 


       5个Processor类列表如下: 


    类名 
  

    是否BeanDefinitionRegistryPostProcessor 
  

是否BeanFactoryPostProcessor

是否BeanPostProcessor

ConfigurationClassPostProcessor

AutowiredAnnotationBeanPostProcessor

    否 
  

    否 
  

    是 
  

CommonAnnotationBeanPostProcessor

    否 
  

    否 
  

    是 
  

EventListenerMethodProcessor

    否 
  

    是 
  

    否 
  

DefaultEventListenerFactory

    否 
  

    否 
  

    否 
  

       ConfigurationClassPostProcessor中两个核心方法将被调用,其主要作用如下: 

方法名

作用

postProcessBeanDefinitionRegistry()

(1)@Conditional注解条件解析

(2)被以下注解标注的类及内部类

@Component、@PropertySources、@PropertySource、@ComponentScans、@ComponentScan、@Import、@ImportResource、@Bean、接口中的@Bean

postProcessBeanFactory()

对full模式的配置类BeanDefinition进行CGLib增强:把CGLib生成的子类型设置到beanDefinition中

       postProcessBeanDefinitionRegistry()源码及注释如下: 

    @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(registry)方法,其主体逻辑流程图如下: 

       其中标红步骤为两个关键步骤: 

** 1. 通过beanDefinition判断是否为配置类**

    Spring专门提供了一个工具类:ConfigurationClassUtils来检查是否为配置类,并标记full、lite模式,逻辑如下:

** 2. 解析配置类**

       doProcessConfigurationClass即为真正的对个注解的解析方法,其逻辑流程图如下: 

    具体的源码及详细注释如下:

    1. 主流程processConfigBeanDefinitions方法:
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
        // 候选配置类定义列表
        List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
        // 获取容器中所有bean定义的名字
        String[] candidateNames = registry.getBeanDefinitionNames();

        for (String beanName : candidateNames) {
            // 获取bean定义
            BeanDefinition beanDef = registry.getBeanDefinition(beanName);
            // org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass
            // Bean Definition是否已经被标记为配置类(full、lite模式)
            if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
                }
            }
            // 查看bean是否是ConfigurationClass
            //被@Configuration、@Component、@ComponentScan、@Import、@ImportResource、@Bean标记
            else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
                // 是配置类,则加入到候选列表
                configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
            }
        }

        // Return immediately if no @Configuration classes were found
        // 如果为空,即找不到被@Configuration、@Component、@ComponentScan、@Import、@ImportResource、@Bean标记的类,则立即返回
        if (configCandidates.isEmpty()) {
            return;
        }

        // Sort by previously determined @Order value, if applicable
        // 对需要处理的BeanDefinition排序,值越小越靠前
        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
        // 检查是否有自定义的beanName生成器
        SingletonBeanRegistry sbr = null;
        if (registry instanceof SingletonBeanRegistry) {
            sbr = (SingletonBeanRegistry) registry;
            if (!this.localBeanNameGeneratorSet) {
                //获取自定义的beanName生成器
                BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
                        AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
                if (generator != null) {
                    // 如果spring有自定义的beanName生成器,则重新赋值
                    this.componentScanBeanNameGenerator = generator;
                    this.importBeanNameGenerator = generator;
                }
            }
        }

        //如果环境对象为空,则创建新的环境对象
        if (this.environment == null) {
            this.environment = new StandardEnvironment();
        }

        // 构造一个配置类解析器,用来把bean定义的重要信息提取转化为ConfigurationClass
        // 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);
        // 存储已解析的配置类列表
        Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
        do {
            // 解析配置类
            parser.parse(candidates);
            // 配置类不能被申明为final(因为CGLIB的限制),除非它声明proxyBeanMethods=false
            // 在@Configuration类中,@Bean方法的实例必须是可重写的,以适应CGLIB
            parser.validate();

            // 获取解析器中解析出的配置类ConfigurationClass: parser.getConfigurationClasses()
            Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
            // 过滤掉已解析的配置类
            configClasses.removeAll(alreadyParsed);

            // 构造一个bean定义读取器
            // 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());
            }
            // 读取ConfigurationClass获取衍生bean定义并注册到容器
            // 核心方法,将完全填充好的ConfigurationClass实例转化为BeanDefinition注册入IOC容器
            this.reader.loadBeanDefinitions(configClasses);
            // 加入已解析配置类
            alreadyParsed.addAll(configClasses);
            // 清空候选配置类定义列表
            candidates.clear();
            // 如果容器中bean定义有新增
            if (registry.getBeanDefinitionCount() > candidateNames.length) {
                // 查找出新增的配置类bean定义 start
                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
        // 如果想要在@Configuration类中使用ImportAware接口,需要将ImportRegistry注册为bean。这样,@Configuration类就可以
        // 使用ImportRegistry来获取导入的类信息
        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.
            // 如果MetadataReaderFactory是由外部提供的,则需要清楚其缓存。但是,如果MetadataReaderFactory是由ApplicationContext共享的,则不需要进行清除,
            // 因为ApplicationContext会自动清楚共享缓存
            ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
        }
    }
    2. 其中检查是否为配置类方法ConfigurationClassUtils.checkConfigurationClassCandidate
//检查给定的BeanDefinition是否是一个配置类的候选者(或一个在配置/组件类中声明的嵌套组件类)
    //并对其进行相应的标记处理
    //被@Configuration、@Component、@ComponentScan、@Import、@ImportResource、@Bean标记
    public static boolean checkConfigurationClassCandidate(
            BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {

        //获取bean定义信息中的class类名
        String className = beanDef.getBeanClassName();
        //如果className为空,或者bean定义信息中的factoryMethod不等于空,那么直接返回
        if (className == null || beanDef.getFactoryMethodName() != null) {
            return false;
        }

        AnnotationMetadata metadata;
        //通过注解注入的BeanDefinition都是AnnotatedGenericBeanDefinition,实现了AnnotatedBeanDefinition
        //Spring内部的BeanDefinition都是RootBeanDefiniton,实现了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()) {
            // Check already loaded Class if present...
            // since we possibly can't even load the class file for this Class.
            //获取当前bean对象的Class对象
            Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
            //如果class实例是下面4种类或者接口的子类,父接口等任何一种情况,直接返回
            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();
            }
            catch (IOException ex) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Could not find class file for introspecting configuration annotations: " +
                            className, ex);
                }
                return false;
            }
        }
        // 获取Bean Definition的元数据被@Configuration注解标注的属性字典值
        Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
        // 如果bean被@Configuration注解标注,并且proxyBeanMethods属性的值为true,则标注当前配置类为full,即需要代理增强,为一个代理类
        if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
            beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
        }
        // 如果存在,或者isConfigurationCandidate返回true,则标注当前配置类为lite,即不需要代理增强,为一个普通类
        // 标注了Configuration注解且proxyBeanMethods属性的值为false,则为lite模式
        // 没有标注Configuration注解,但是标注了Component、ComponentScan、Import、ImportResource、@Bean注解、则为lite模式
        else if (config != null || isConfigurationCandidate(metadata)) {
            beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
        }
        // 组件类不存在@Configuration注解,直接返回false
        else {
            return false;
        }

        // 获取配置类的排序顺序,设置到组件定义属性中
        // It's a full or lite configuration candidate... Let's determine the order value, if any.
        //Bean Definition是一个标记为full/lite的候选项,如果有order属性就设置order属性
        Integer order = getOrder(metadata);
        if (order != null) {
            //设置bean的order值
            beanDef.setAttribute(ORDER_ATTRIBUTE, order);
        }

        return true;
    }
    3. 真正干活的方法doProessConfigurationClass
// 通过读取源类的注释、成员和方法来构建完整的ConfigurationClass
    // 1.处理@Component
    // 2.处理每个@PropertySource
    // 3.处理每个@ComponentScan
    // 4.处理每个Impoit
    // 5.处理每个@ImportResource
    // 6.找配置类中@Bean注解的方法(找出Class中存在@Bean标注的方法,加入到ConfigurationClass的beanMethods属性)
    // 7.找接口中@Bean注解的方法
    // 8.存在父类则递归处理
    @Nullable
    protected final SourceClass doProcessConfigurationClass(
            ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
            throws IOException {

        if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
            // Recursively process any member (nested) classes first
            // 递归处理嵌套的成员类
            processMemberClasses(configClass, sourceClass, filter);
        }

        // Process any @PropertySource annotations
        // 处理@PropertySources和@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");
            }
        }

        // Process any @ComponentScan annotations
        // 处理@ComponentScans和@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) {
                // The config class is annotated with @ComponentScan -> perform the scan immediately
                // 配置类使用了注解@ComponentScan -> 立即执行扫描。
                Set<BeanDefinitionHolder> scannedBeanDefinitions =
                        this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
                // Check the set of scanned definitions for any further config classes and parse recursively if needed
                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());
                    }
                }
            }
        }

        // Process any @Import annotations
        // 处理@Import注解
        // getImports:递归获取@Import导入的类
        processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

        // Process any @ImportResource annotations
        // 处理@ImportResource注解
        // 读取locations, reader属性,封装存放在importResources map集合中
        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);
            }
        }

        // Process individual @Bean methods
        // 处理@Bean方法
        Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
        for (MethodMetadata methodMetadata : beanMethods) {
            configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
        }

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

本文转载自: https://blog.csdn.net/zhangweiocp/article/details/134147060
版权归原作者 zhangweiocp 所有, 如有侵权,请联系我们删除。

“Spring IOC - ConfigurationClassPostProcessor源码解析”的评论:

还没有评论