• 分析-ConfigurationClassPostProcessor原理


    目录

    一、概述

    二、运行流程

    1、refresh()

    2、processConfigBeanDefinitions()

    3、processConfigurationClass()

    4、doProcessConfigurationClass()


    一、概述

    ConfigurationClassPostProcessor是用来容器启动时处理解析容器的配置类,实现了BeanDefinitionRegistryPriorityOrdered接口。

    当容器开启组件扫描或使用ComponentScan会默认注册到容器中,否则,将如同其他的BeanFactoryPostProcessor后置处理器一样手动被声明到容器中。

    配置类通过ConfigurationClassUtils工具类判断:

    1、标识@Configuration注解

    2、标识@Component、@ComponentScan、@Import、@ImportResource、方法标识@Bean

     

    二、运行流程

    1、refresh()

    创建容器时,在refresh方法中调用invokeBeanFactoryPostProcessors方法创建运行BeanFactory后置处理器。

    进入invokeBeanFactoryPostProcessors方法的PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors方法, ConfigurationClassPostProcessor由于实现了BeanDefinitionRegistryPriorityOrdered接口,在如图红框被容器扫描出来并创建对象,在invokeBeanDefinitionRegistryPostProcessors方法中运行ConfigurationClassPostProcessorpostProcessBeanDefinitionRegistry方法。

    ConfigurationClassPostProcessorpostProcessBeanDefinitionRegistry方法主要是设置registryId,防止postProcessBeanDefinitionRegistry方法被多次调用,processConfigBeanDefinitions方法开始解析配置类。

    2、processConfigBeanDefinitions()

    processConfigBeanDefinitions方法中遍历容器的beanDefinition集合,通过ConfigurationClassUtils工具类找到配置类beanDefinition,将其放入configCandidates集合中。

    创建ConfigurationClassParser对象,调用对象的parse方法对配置类进行解析。

    进入parse方法,根据bd的类型进入不同的parse方法,而那些parse方法都调用一个processConfigurationClass方法。

    3、processConfigurationClass()

    先根据配置类是否标识了@Conditional,判断是否跳过不解析。

    通过doProcessConfigurationClass方法对配置类信息进行详细解析,若是当前配置类含有父类(排除java开头的类,例如Object),则会返回该配置类的父类,进行对父类进行解析,然后最后将已解析的配置类放到configurationClasses集合中,防止多次解析。

    4、doProcessConfigurationClass()

    该方法主要是解析多个spring注解,例如@PropertySource、@ComponentScan、@Import、@ImportResource、@Bean、解析配置类的内部类等。

    进入doProcessConfigurationClass方法,先判断该配置类是否含有@Component注解(isAnnotated方法会找当前类标识的注解,包括注解内部的元注解),

    若是有,则通过processMemberClasses方法会遍历配置类定义的内部类,判断内部类是否是配置类,若是则将内部类放入candidates集合中,并遍历candidates集合调用processConfigurationClass方法解析。

    1. private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
    2. Collection memberClasses = sourceClass.getMemberClasses();
    3. if (!memberClasses.isEmpty()) {
    4. List candidates = new ArrayList<>(memberClasses.size());
    5. for (SourceClass memberClass : memberClasses) {
    6. if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
    7. !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
    8. candidates.add(memberClass);
    9. }
    10. }
    11. OrderComparator.sort(candidates);
    12. for (SourceClass candidate : candidates) {
    13. if (this.importStack.contains(configClass)) {
    14. this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
    15. }
    16. else {
    17. this.importStack.push(configClass);
    18. try {
    19. processConfigurationClass(candidate.asConfigClass(configClass));
    20. }
    21. finally {
    22. this.importStack.pop();
    23. }
    24. }
    25. }
    26. }
    27. }

    接着解析配置类的@PropertySource,解析配置文件并加载到容器环境中。

    解析@ComponentScan组件,扫描得到beanDefinition集合,若是扫描中包含配置类,则会调用parse方法先解析该配置类

     接下来解析@Import组件,解析详情可参考解析@Import底层原理_Just-Today的博客-CSDN博客

     解析@ImportResource

     解析@Bean

    最后判断该配置类是否继承类名不是java开头的父类,且父类不在knownSuperclasses集合中,若是有则返回该配置类的父类,继续解析父类,若是没,则返回null结束解析循环方法。

    至此,通过解析将容器中的所有配置类、通过解析注解得到的beanDefinition都被保存到容器的beanDefinitions集合中。

  • 相关阅读:
    【JVM篇】有哪些垃圾回收算法
    死锁,死锁避免
    Java集合collection map stream流
    springboot4:总结前3(图解)
    C++ Reference: Standard C++ Library reference: C Library: cctype
    网络相关知识
    电影售票系统遇到的问题
    隐私协议 Secret Network 宣布使用 Octopus Network 构建的 NEAR-IBC 连接 NEAR 生态
    牛客网---活动运营刷题笔记
    43、基于 springboot 自动配置的 spring mvc 错误处理,就是演示项目报错后,跳转到自定义的错误页面
  • 原文地址:https://blog.csdn.net/weixin_37607613/article/details/126228867