likes
comments
collection
share

12.postProcessBeanDefinitionRegistry源码(上)

作者站长头像
站长
· 阅读数 9

所以分为2部分去讲。

第一部分主要是讲遍历候选的BeanDefinition,然后根据BeanDefinition的属性configClass判断是否是配置类,如果是配置类加入候选配置类集合,第二部分对候选配置类集合进行解析。

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        // 一个工厂的后置处理器只会执行一次
        // 具体逻辑是根据对象的hashCode判断是否被调用过
        int registryId = System.identityHashCode(registry);
        //如果被调用过 那么
        if (this.registriesPostProcessed.contains(registryId)) {
           throw new Exception("postProcessBeanDefinitionRegistry already called");
        }
        if (this.factoriesPostProcessed.contains(registryId)) {
            throw new Exception("postProcessBeanDefinitionRegistry already called");
        }
        this.registriesPostProcessed.add(registryId);
        //重点代码跟进去!!!
        //重点代码跟进去!!
        //重点代码跟进去!
        processConfigBeanDefinitions(registry);
    }

ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry(registry)的核心逻辑在processConfigBeanDefinition()方法中。

processConfigBeanDefinitions源码

      public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
            List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
            /**
             * registry就是DefaultListableBeanFactory
             * DefaultListableBeanFactory是bean工厂
             * 步骤1.获取所有已经注册的beanName放入候选数组candidateNames
             */
            String[] candidateNames = registry.getBeanDefinitionNames();
            
            /**
             * 步骤2.遍历candidateNames对应的BeanDefinition,判断BeanDefinition是否是配置类
             * 如果是配置类将BeanDefinition加入configCandidates
             * 比如下面配置类,找到配置类后spring就知道从哪里开始扫描啦
             *  @ComponentScan("com")
             *  public class Config { 
             *  }
             */
            for (String beanName : candidateNames) {
                // 根据beanName获得BeanDefinition
                BeanDefinition beanDef = registry.getBeanDefinition(beanName);
                /*  
                BeanDefinition中有这么一个变量attributes,类型为LinkedHashMap
                Map<String, Object> attributes = new LinkedHashMap<>();
                用来存储属性值,如果该attributes中存在configurationClass这个key
                且对应的值是full或者lite,意味着已经处理过了,直接跳过。
                后面处理BeanDefinition时会给bd设置一个属性
                key为configurationClass,value为full或者lite
                 */
                //如果是 FULL 或者 LITE  那么跳过
                if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                        ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
                   //啥也不做 说明被处理过了
                }
                /* 
                 checkConfigurationClassCandidate方法会判断是否是配置类
                 并为BeanDefinition设置属性configurationClass为lite或者full或者false
                 如果加了@Configuration,那么对应的BeanDefinition为full。
                 如果加了@Component,@ComponentScan,@Import,@ImportResource这些注解
                 或者是带有@Bean方法的类,则为lite。
                 如果不是lite和full 返回的是false
                 lite和full均表示这个BeanDefinition对应的类是一个配置类
                 为BeanDefinition设置lite和full属性值是为了后面在使用
                 具体可看代码 1.checkConfigurationClassCandidate
                */ 
                else if(ConfigurationClassUtils.checkConfigurationClassCandidate
                                              (beanDef, this.metadataReaderFactory)){
                    //添加到候选配置集合中,后面统一处理
                   //BeanDefinitionHolder对BeanDefinition和名字做了简单封装
                    configCandidates.add
                            (new BeanDefinitionHolder(beanDef, beanName));
                }
            }
            
            //configCandidates放的是候选配置类
            //即带有如下注解的类
            //@Configuration  @Component @ComponentScan @Import @ImportResource
            //或者是带有@Bean方法的类                        
            //如果没有候选配置类,就直接返回,啥也不执行
            if (configCandidates.isEmpty()) {
                return;
            }
            
            //步骤3
            //将配置类进行排序
                //我们可以提供多个配置类,然后在配置类上添加@Order注解决定配置类的先后调用顺序
            configCandidates.sort((bd1, bd2) -> {
                int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
                int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
                return Integer.compare(i1, i2);
            });
            
            /**
             * 判断是否有自定义的beanName生成器,没有话就用默认的BeanNameGenerator
             * 因为后面会扫描出所有加入到spring容器中calss类
             * 然后把这些class解析成BeanDefinition类
             * 此时需要利用BeanNameGenerator为这些BeanDefinition生成beanName
             * 默认的BeanNameGenerator是类名首字母小写
             */
            SingletonBeanRegistry sbr = null;
          // DefaultListableBeanFactory是SingletonBeanRegistry类型
            if (registry instanceof SingletonBeanRegistry) {
                sbr = (SingletonBeanRegistry) registry;
                //localBeanNameGeneratorSet = false
                if (!this.localBeanNameGeneratorSet) {
                    //步骤4
                    //获取internalConfigurationBeanNameGenerator
                    //返回的是null
                    BeanNameGenerator generator = (BeanNameGenerator) 
                                sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
                    if (generator != null) {
                        this.componentScanBeanNameGenerator = generator;
                        this.importBeanNameGenerator = generator;
                    }
                }
            }
    
            if (this.environment == null) {
                this.environment = new StandardEnvironment();
            }
            
            /**
             * 实例化ConfigurationClassParser是为了解析各个配置类即带@Configuration注解的类
             * 初始化ConfigurationClassParser的一些属性
             */
            ConfigurationClassParser parser = new ConfigurationClassParser(
                                            this.metadataReaderFactory, 
                                            this.problemReporter, this.environment,
                                            this.resourceLoader, 
                                            this.componentScanBeanNameGenerator, 
                                            registry);
            /**
             * 实例化两个set
             * candidates用于保存候选配置类
             * alreadyParsed用于保存已经解析过的配置类
             */
            Set<BeanDefinitionHolder> candidates = 
                                        new LinkedHashSet<>(configCandidates);
            Set<ConfigurationClass> alreadyParsed = 
                                        new HashSet<>(configCandidates.size());
            //注意 这个 doWhile是在for循环里
            do {
                // 开始扫描/注册包下的类
                // 在此处会解析配置类上的注解
                // 这一步只会将加了@Configuration注解以及@ComponentScan注解扫描的类加入到
                // BeanDefinitionMap中
                // 通过其他注解(例如@Import、@Bean)的方式,在parse()方法并不会将其解析为                           // BeanDefinition放入到BeanDefinitionMap中
                // 真正放入到map中是在下面的this.reader.loadBeanDefinitions()方法中实现的
                parser.parse(candidates);
                parser.validate();
                //获取本次扫描到的所有configurationClasses
                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());
                }
                // 在这里统一处理,没有注册的进行注册
                // 将上一步parser解析出的ConfigurationClass类加载成BeanDefinition
                // 实际上经过上一步的parse()后,解析出来的bean已经放入BeanDefinitionMap中
                // 但是由于这些bean可能会引入新的bean
                // 例如实现了ImportBeanDefinitionRegistrar或者ImportSelector接口的bean
                // 或者bean中存在被@Bean注解的方法
                // 因此需要执行一次loadBeanDefinition()去
                // 处理ImportBeanDefinitionRegistrar或者@Import或者@从ImportedResource
                // 或者@Bean修饰的方法 来加载bd
                this.reader.loadBeanDefinitions(configClasses);
                alreadyParsed.addAll(configClasses);
                candidates.clear();
                // 这里判断registry.getBeanDefinitionCount() > candidateNames.length
                // 目的是为了知道reader.loadBeanDefinitions(configClasses)
                // 这一步有没有向BeanDefinitionMap中添加新的BeanDefinition
                // 实际上就是看配置类(例如AppConfig类会向BeanDefinitionMap中添加bean)
                // 如果有,registry.getBeanDefinitionCount()就会大candidateNames.length
                // 这样就需要再次遍历新加入的BeanDefinition,并判断这些bean是否已经被解析过了
                // 如果未解析,需要重新进行解析
                // 这里的AppConfig类向容器中添加的bean
                // 实际上在parser.parse()这一步已经全部被解析了
                // 所以为什么还需要做这个判断,目前没看懂,似乎没有任何意义。
                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());
                    }
                    // 如果有未解析的类,则将其添加到candidates中
                    // 这样candidates不为空,就会进入到下一次的while的循环中
                    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());
            
          
            if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
                sbr.registerSingleton
                    (IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
            }

            if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
                ((CachingMetadataReaderFactory) 
                    this.metadataReaderFactory).clearCache();
            }
        }

步骤总结

步骤1:遍历所有的BeanDefinitionName

方法伊始,我们拿到容器中所有的BeanDefinition的名字,包括系统内置的5个后置处理器及我们提供的Config配置类。

12.postProcessBeanDefinitionRegistry源码(上)

紧接着,循环遍历这些BeanDefinition,过滤掉spring内置的后置处理器,留下我们提供的配置类,解析配置类,完成扫描和注册,这个配置类只能解析使用一次。

那么spring如何过滤出我们提供的配置类以及如何保证只解析使用一次呢?

保证使用一次很简单,只要第一次解析使用完成后添加一个标志即可。在BeanDefinition维护一个变量, Map<String, Object> attributes = new LinkedHashMap<>();用来存储属性值。

如果该attributes中存在configurationClass这个键,且对应的值是full或者lite意味着已经处理过了,直接跳过。

下面的源码就是判断是否有该键值的:

     private static final String CONFIGURATION_CLASS_FULL = "full";
        private static final String CONFIGURATION_CLASS_LITE = "lite";

        public static boolean isFullConfigurationClass(BeanDefinition beanDef) {
            return CONFIGURATION_CLASS_FULL
                        .equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
        }

        public static boolean isLiteConfigurationClass(BeanDefinition beanDef) {
            return CONFIGURATION_CLASS_LITE
                        .equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
        }

            //如果是@Configuration 就是full
    public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
            return metadata.isAnnotated(Configuration.class.getName());
        }
            //如果是下面这些注解修饰的类或者是带有@Bean的方法类 就是Lite
            /*
            candidateIndicators.add(Component.class.getName());
            candidateIndicators.add(ComponentScan.class.getName());
            candidateIndicators.add(Import.class.getName());
            candidateIndicators.add(ImportResource.class.getName());
            */
    public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {
             
            if (metadata.isInterface()) {
                return false;
            }
            //下面这些注解修饰的类
            for (String indicator : candidateIndicators) {
                if (metadata.isAnnotated(indicator)) {
                    return true;
                }
            }
            //带有@Bean的方法类
            return metadata.hasAnnotatedMethods(Bean.class.getName());
        }

最关键的是如何筛选出我们的配置类?答案就是根据类型。

文章开头,我们通过代码往spring中添加我们的配置类context.register(Config.class);,我们跟进这行代码看spring是如何把Config转成BeanDefinition的,一直跟到doRegisterBean方法:

            //beanClass就是Config.class
            AnnotatedGenericBeanDefinition abd = 
                                    new AnnotatedGenericBeanDefinition(beanClass);
            //... 中间省略...
            BeanDefinitionHolder definitionHolder = 
                                    new BeanDefinitionHolder(abd, beanName);
            definitionHolder = AnnotationConfigUtils
                    .applyScopedProxyMode
                        (scopeMetadata, definitionHolder, this.registry);
            BeanDefinitionReaderUtils
                    .registerBeanDefinition(definitionHolder, this.registry);

由此可见自定义的Config被转成了AnnotatedGenericBeanDefinition类型,还记得之前讲过的BeanDefinition继承图吗,笔者不厌其烦的再次祭出BeanDefinition的继承图:

12.postProcessBeanDefinitionRegistry源码(上)

AnnotatedGenericBeanDefinition在最底层右面第二个的位置。上文中的“注册时机”我们能看到,spring内置的后置处理器都是RootBeanDefinition类型的。

由此可见AnnotatedGenericBeanDefinition和RootBeanDefinition没有半毛钱关系,我们自然通过instanceof类型匹配关键字过滤出我们的配置类了!分析过滤的源码:

    else if (ConfigurationClassUtils
                .checkConfigurationClassCandidate
                    (beanDef, this.metadataReaderFactory)) {
                        configCandidates
                            .add(new BeanDefinitionHolder(beanDef, beanName));
                }

<!---->

    public static boolean checkConfigurationClassCandidate(
            BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {

            String className = beanDef.getBeanClassName();
            if (className == null || beanDef.getFactoryMethodName() != null) {
                return false;
            }

            AnnotationMetadata metadata;
            if (beanDef instanceof AnnotatedBeanDefinition &&
                    className.equals(((AnnotatedBeanDefinition) 
                                        beanDef).getMetadata().getClassName())) {
                
                metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
            }else if (beanDef instanceof AbstractBeanDefinition && 
                                ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
                
                Class<?> beanClass = 
                        ((AbstractBeanDefinition) beanDef).getBeanClass();
                metadata = new StandardAnnotationMetadata(beanClass, true);
            }else {
                try {
                    MetadataReader metadataReader =     
                            metadataReaderFactory.getMetadataReader(className);
                    metadata = metadataReader.getAnnotationMetadata();
                }
                catch (IOException ex) {
                    return false;
                }
            }
            //判断是否存在@Configuration注解
            //设置为FULL
            if (isFullConfigurationCandidate(metadata)) {
                beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
            }
            //判断是否存在@Bean修饰的方法的类或者被以下注解修饰的类
            //设置为LITE
            /*
            candidateIndicators.add(Component.class.getName());
            candidateIndicators.add(ComponentScan.class.getName());
            candidateIndicators.add(Import.class.getName());
            candidateIndicators.add(ImportResource.class.getName());
            */
            else if (isLiteConfigurationCandidate(metadata)) {
                beanDef.setAttribute
                    (CONFIGURATION_CLASS_ATTRIBUTE,CONFIGURATION_CLASS_LITE);
            }
            else {
                return false;
            }

            //解析order的value值作为属性设置进去
            Integer order = getOrder(metadata);
            if (order != null) {
                beanDef.setAttribute(ORDER_ATTRIBUTE, order);
            }
            return true;
        }

步骤2:如果符合以下条件,那么加入集合

@Configuration = full

@Component = lite

@Service = lite

@Component
public @interface Service {}

@Controller = lite

@Component
public @interface Controller {}

@Repository = lite

public @interface Repository {}

@ComponentScan = lite

@ComponentScans = lite

@ComponentScans({@ComponentScan(""),@ComponentScan("")})

@Import = lite

@ImportResource = lite

带@Bean注解的方法 = lite

跟进checkConfigurationClassCandidate这行代码,这行代码的意思是找到我们的配置类并获取到他的注解信息。

如果注解包含了@Configuration,则设置属性键值对configurationClass=full,会加入候选集合。

否则判断注解是否包含@Component、@ComponentScan、@Import、@ImportResource、@Bean注解的方法。如果是则设置键值对configurationClass=lite,会加入候选集合。

如果都不是则返回false,说明Config不是配置类,不会加入候选集合中。

看源码:

    public static boolean checkConfigurationClassCandidate(
                BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
            //获取class名字,这里是com.config.Config
            String className = beanDef.getBeanClassName();

            if (className == null || beanDef.getFactoryMethodName() != null) {
                return false;
            }
            AnnotationMetadata metadata;
            //判断BeanDefinition是否是AnnotatedBeanDefinition类型, 
            //AnnotatedGenericBeanDefinition实现了AnnotatedBeanDefinition
            //我们的配置类Config对应的BeanDefinition确实就是AnnotatedBeanDefinition类型
            if (beanDef instanceof AnnotatedBeanDefinition &&
                    className.equals(((AnnotatedBeanDefinition) 
                                      beanDef).getMetadata().getClassName())) {
                //获取配置类的注解信息
                metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
            }
            //如果BeanDefinition是AbstractBeanDefinition并且包装了业务类,  
            //RootBeanDefinition继承了如果BeanDefinition是AbstractBeanDefinition
            //spring内置的后置处理器确实是AbstractBeanDefinition类型的
            else if (beanDef instanceof AbstractBeanDefinition && 
                     ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
                //beanClass  =  ConfigurationClassPostProcesso
                Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
                //拿到注解信息
                metadata = new StandardAnnotationMetadata(beanClass, true);
            }else {
                try {
                    //既不是AnnotatedBeanDefinition类型也不是AbstractBeanDefinition类型
                    //或者是AbstractBeanDefinition类型但没有包装业务类
                    MetadataReader metadataReader = 
                            metadataReaderFactory.getMetadataReader(className);
                    metadata = metadataReader.getAnnotationMetadata();
                }
                catch (IOException ex) {
                    return false;
                }
            }
            //判断注解中是否包含了@Configuration注解
            if (isFullConfigurationCandidate(metadata)) {
                //设置属性,相当于beanDef.setAttribute("configurationClass","full")
                beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, 
                                                    CONFIGURATION_CLASS_FULL);
            }
            //判断注解中是否包含了@Component、ComponentScan、Import、ImportResource其中之一
            //或者是否有@Bean注解的方法。
            else if (isLiteConfigurationCandidate(metadata)) {
                //设置属性,相当于beanDef.setAttribute("configurationClass","lite")
                beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, 
                                                    CONFIGURATION_CLASS_LITE);
            }else {
                //实际上,如果你打断点仔细运行,你会发现,spring内置后置处理器都没有上面那些注解
                return false;
            }

            //如果有@Order注解,拿到注解的value值,并将值设置到属性中,后面执行会根据这个属性值的大小进行先后调用
            Integer order = getOrder(metadata);
            if (order != null) {
                beanDef.setAttribute(ORDER_ATTRIBUTE, order);
            }
            return true;
        }

由此可知,所谓的配置类就是要么含有@Configuration注解,要么含有@Component、@ComponentScan、@Import、@ImportResource其中之一,要么类中含有@Bean注解的方法。

注意其中 @Component包括他的子注解@Service、@Controller、@Repository。spring后续根据这些注解完成扫描和注册。 ​ 实际上上面的代码运行结束后,只有我们的配置类Config对应的BeanDefinition完成了属性值的设置,且返回true,最后添加到集合configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));。spring内置的后置处理器都没有上面所说的注解所以返回false,自然不会添加到集合中。源码中我也解释清楚了,希望读者仔细阅读思考,有疑问打在留言区一起探讨,我会一一回复。

    //如果扫描完毕没有配置类就直接返回
    if (configCandidates.isEmpty()) {
      return;
    }

如果,我们没有提供配置类,直接返回,后续也不会扫描和注册。也就是我们自定义的bean不会被引入。

运行到这里的时候我们注册了自定义配置类对应的BeanDefinition, 并且BeanDefinition对应的属性configurationClass是full。

步骤3:对配置类进行排序

     configCandidates.sort((bd1, bd2) -> {
                int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
                int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
                return Integer.compare(i1, i2);
            });

上面checkConfigurationClassCandidate代码中的最后处理了@Order注解,将他的值放到了属性中,在这里,如果你有多个配置类,进行排序,后面会按照顺序进行处理。打个比方:

    @ComponentScan("com")
    @Order(1)
    public class Config {
    }

    @Service
    @Order(2)
    public class Config2 {
    }

    public class SpringTest {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
            context.register(Config.class);
            context.register(Config2.class);
            context.refresh();
        }
    }

12.postProcessBeanDefinitionRegistry源码(上)

步骤4:获取BeanName生成器

    SingletonBeanRegistry sbr = null;
            /**
             * 由于当前传入的是DefaultListableBeanFactory是SingletonBeanRegistry的子类
             */
            if (registry instanceof SingletonBeanRegistry) {
                sbr = (SingletonBeanRegistry) registry;
                /**
                 * 判断是否有自定义的beanName生成器
                 */
                if (!this.localBeanNameGeneratorSet) {
                    BeanNameGenerator generator = (BeanNameGenerator) 
                                sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
                    // 获取spring默认的beanName生成器,这里为空
                    if (generator != null) {
                        /**
                         * componentScanBeanNameGenerator与importBeanNameGenerator定义时                     * 就赋值了new AnnotationBeanNameGenerator()
                         * 如果spring有默认的beanName生成器,则重新赋值
                         */
                        this.componentScanBeanNameGenerator = generator;
                        this.importBeanNameGenerator = generator;
                    }
                }
            }

说实话,笔者不是很关心这几行源码,大概意思就是如果你提供了自定义的名字生成器那就用你的,否则spring用自己默认的名字生成器,我知道是Class类名首字母小写。读者可研究下名字生成器类AnnotationBeanNameGenerator,很简单。

它实现了BeanNameGenerator接口,这个接口只有一个String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry);方法,你可以实现这个接口生成自定义名字生成器。打个比方:

    /自定义名字生成器
    public class MyNameGenerator implements BeanNameGenerator {
        @Override
        public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
            return definition.getBeanClassName()+"源码之路";
        }
    }

    public class SpringTest {

        public static void main(String[] args) {


            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
            context.register(Config.class);
            //创建一个名字生成器类
            MyNameGenerator myNameGenerator = new MyNameGenerator();
    //通过上面的源码可知,必须以单例的方式注册的bean工厂中
            context.getBeanFactory()
                        .registerSingleton
                        (AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
                        myNameGenerator);
            context.refresh();
            System.out.println();
        }
    }

12.postProcessBeanDefinitionRegistry源码(上)

在读此篇博客之前,如果你要生成一个自定义名字生成器你怎么做?查百度对吧,百度没有呢?spring源码重要吗?不重要,工作中会用spring就行,我关注业务就行,谁会关注源码?谁会关注?你的技术领导会,你们的CTO会,因为他是建筑师,而你是建筑工人。我没有吹嘘我自己,我只是强调spring源码对你的整个职业生涯起着至关重要的作用。

继续往下看:

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

标准资源环境,以后专门写一篇博客讲解环境抽象。

上面我们拿到了配置类集合configCandidates,下一步就是解析处理这些配置类。鉴于解析篇幅太长所以放在下一篇文章。

下一篇文章可以带着问题去读。

1.@Configuration作用?

2.如何解析@Configuration的类?

3.解析@ComponentScan时机?

4.解析@Import注解时机,如何解析的?

5.解析@Bean注解的时机?