zoukankan      html  css  js  c++  java
  • BeanFactory后置处理器

    接 springIOC - ConfigurationClassPostProcessor - full / lite  

    代码块:

    org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions

    do {
        parser.parse(candidates);
        parser.validate();
        //map.keyset
        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());
        }
    
        /**
         * 这里值得注意的是扫描出来的bean当中可能包含了特殊类
         * 比如ImportBeanDefinitionRegistrar那么也在这个方法里面处理
         * 但是并不是包含在configClasses当中
         * configClasses当中主要包含的是importSelector
         * 因为ImportBeanDefinitionRegistrar在扫描出来的时候已经被添加到一个list当中去了
         */
    
        //将 bd 放到 map 中
        this.reader.loadBeanDefinitions(configClasses);
        alreadyParsed.addAll(configClasses);
    
        candidates.clear();
        //由于我们这里进行了扫描,把扫描出来的BeanDefinition注册给了factory
        //但是
        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());

    parse 解析完后, 就会调用 loadBeanDefinitions方法.

    这方法会将 StartConfig.java 解析出来的一些 bd, 注册到spring容器中.

    public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
        TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
        for (ConfigurationClass configClass : configurationModel) {
            loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
        }
    }

    这个方法里面, 就会对配置文件中的 @Bean 进行注册,

    然后会调用 前面解析到的 ImportBeanDefinitionRegistrar.registerBeanDefinitions 方法. 

    private void loadBeanDefinitionsForConfigurationClass(
            ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
    
        if (trackedConditionEvaluator.shouldSkip(configClass)) {
            String beanName = configClass.getBeanName();
            if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
                this.registry.removeBeanDefinition(beanName);
            }
            this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
            return;
        }
    
        // 注册 @Import 导入的普通 bean , 或者 ImportSelector 导入的普通bean
        if (configClass.isImported()) {
            registerBeanDefinitionForImportedConfigurationClass(configClass);
        }
        //@Bean 的注册
        for (BeanMethod beanMethod : configClass.getBeanMethods()) {
            loadBeanDefinitionsForBeanMethod(beanMethod);
        }
    
         //xml
        loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    
        //注册Registrar
        loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
    }

    这里需要特别注意一下 loadBeanDefinitionsForBeanMethod

    他是对 @Bean 进行注册的, 有一段代码比较重要

    ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
    beanDef.setResource(configClass.getResource());
    beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
    
    //如果 method 是静态的
    if (metadata.isStatic()) {
        // static @Bean method 
       // static时, 设置的是 BeanClassName 属性
    beanDef.setBeanClassName(configClass.getMetadata().getClassName()); beanDef.setFactoryMethodName(methodName); } else { //非static的 method, 设置了一个 FactoryBeanName 属性 // instance @Bean method beanDef.setFactoryBeanName(configClass.getBeanName()); beanDef.setUniqueFactoryMethodName(methodName); } beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);

    这里配置了构造函数自动注入模式

    实例代码:

    @Configuration
    public class AppConfig {
    
        @Bean
        public static A a(){
            return new A();
        }
    
        @Bean
        public B b(){
            a();
            return  new B();
        }
    }

    这里对 A 和 B 都进行了解析, 转化成了 ConfigurationClassBeanDefinition 

    1.静态方法时, 设置的

    BeanClassName = "xxx.xxx.xxx.AppConfig"

    FactoryMethodName = "a"

    创建的时候, 会来找 AppConfig的a()

    2.非静态方法时, 设置的

    FactoryBeanName = "xxx.xxx.xxx.AppConfig"

    UniqueFactoryMethodName = "b"

    创建 b 的时候, 会来这里找 b() 方法

  • 相关阅读:
    ArcEngine+C# TIN相关三维功能模块介绍(三)
    关于“实践”的一点认识
    浅析:C# 中构建多线程应用程序
    ArcEngine+C# TIN相关三维功能模块介绍(二)
    论文分享NO.1(by_xiaojian)
    【第2次会议记录_2018.5.27】—— [ 算法原理 ]:手工特征提取的概念问题。(by_wanghao)
    UK Day46 MongoDB 启动和连接MongoDB
    UK Day42 Mac修改Terminal主题
    UK Day45 什么是云计算
    性能优化小结
  • 原文地址:https://www.cnblogs.com/elvinle/p/13245884.html
Copyright © 2011-2022 走看看