面试官:Spring如何解析配置类

news2024/12/25 1:20:28

你好,我是柳岸花开。

大家好,今天我们来深入探讨一下Spring框架中的配置类解析与扫描过程的源码。Spring作为Java开发中最为广泛使用的框架之一,其核心机制一直是开发者关注的焦点。本文将带领大家从源码角度,详细剖析Spring配置类的解析与扫描过程。

配置类解析概述

在Spring中,配置类主要是通过注解的方式进行定义和解析的。其中,@Configuration@ComponentScan是两个最为重要的注解。

  • @Configuration:标识一个类为配置类,类似于传统的XML配置文件。
  • @ComponentScan:用于指定Spring在初始化时需要扫描的包路径,从而找到标注了特定注解的类。

这些注解的解析过程是通过Spring的内部机制来实现的,下面我们将一步步解析这个过程。

源码分析

1. @Configuration注解的解析

Spring在启动时,会通过ConfigurationClassPostProcessor类对所有标注了@Configuration注解的类进行处理。其核心方法是processConfigBeanDefinitions,该方法的主要工作是扫描所有的bean定义,并找出配置类进行处理。

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    String[] candidateNames = registry.getBeanDefinitionNames();

    for (String beanName : candidateNames) {
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
        if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
        }
    }
    // 后续处理逻辑
}

在这个过程中,Spring会识别所有的配置类,并进行后续的处理。

2. @ComponentScan注解的解析

配置类被识别后,Spring会继续解析其中的@ComponentScan注解。这个注解的解析逻辑在ClassPathBeanDefinitionScanner类中实现。其核心方法是doScan,该方法会扫描指定包路径下的所有类,并将符合条件的类注册为Bean。

public Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    for (String basePackage : basePackages) {
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        for (BeanDefinition candidate : candidates) {
            beanDefinitions.add(new BeanDefinitionHolder(candidate, generateBeanName(candidate)));
        }
    }
    return beanDefinitions;
}

该方法会递归扫描指定的包路径,并筛选出符合条件的类,注册为Spring的Bean。

解析配置具体步骤

alt
  1. 在启动Spring时,需要传入一个AppConfig.class给ApplicationContext,ApplicationContext会根据AppConfig类封装为一个BeanDefinition,这种BeanDefinition我们把它称为配置类BeanDefinition。
  2. ConfigurationClassPostProcessor中会把配置类BeanDefinition取出来
  3. 构造一个ConfigurationClassParser用来解析配置类BeanDefinition,并且会生成一个配置类对象ConfigurationClass
  4. 如果配置类上存在@Component注解,那么 解析配置类中的内部类(这里有递归,如果内部类也是配置类的话)
  5. 如果配置类上存在@PropertySource注解,那么则解析该注解,并得到PropertySource对象,并添加到environment中去
  6. 如果配置类上存在@ComponentScan注解,那么则解析该注解,进行扫描,扫描得到一系列的BeanDefinition对象,然后判断这些BeanDefinition是不是也是配置类BeanDefinition(只要存在@Component注解就是配置类,所以基本上扫描出来的都是配置类),如果是则继续解析该配置类, (也有递归),并且会生成对应的ConfigurationClass
  7. 如果配置类上存在@Import注解,那么则判断Import的类的类型:
    1. 如果是ImportSelector,那么调用执行selectImports方法得到类名,然后在把这个类当做配置类进行解析 (也是递归)
    2. 如果是ImportBeanDefinitionRegistrar,那么则生成一个ImportBeanDefinitionRegistrar实例对象,并添加到配置类对象中(ConfigurationClass)的 importBeanDefinitionRegistrars属性中。
  8. 如果配置类上存在@ImportResource注解,那么则把导入进来的资源路径存在配置类对象中的 importedResources属性中。
  9. 如果配置类中存在@Bean的方法,那么则把这些方法封装为BeanMethod对象,并添加到配置类对象中的 beanMethods属性中。
  10. 如果配置类实现了某些接口,则看这些接口内是否定义了@Bean的默认方法
  11. 如果配置类有父类,则把父类当做配置类进行解析
  12. AppConfig这个配置类会对应一个ConfigurationClass,同时在解析的过程中也会生成另外的一些ConfigurationClass,接下来就利用reader来进一步解析ConfigurationClass
    1. 如果ConfigurationClass是通过@Import注解导入进来的,则把这个类生成一个BeanDefinition,同时解析这个类上@Scope,@Lazy等注解信息,并注册BeanDefinition
    2. 如果ConfigurationClass中存在一些BeanMethod,也就是定义了一些@Bean,那么则解析这些@Bean,并生成对应的BeanDefinition,并注册
    3. 如果ConfigurationClass中导入了一些资源文件,比如xx.xml,那么则解析这些xx.xml文件,得到并注册BeanDefinition
    4. 如果ConfigurationClass中导入了一些ImportBeanDefinitionRegistrar,那么则执行对应的registerBeanDefinitions进行BeanDefinition的注册

👇关注我,下期了解👇

Spring之整合Mybatis底层源码解析

alt

回复 222,获取Java面试题合集

关于我

一枚爱折腾的Java程序猿,专注Spring干货。把路上的问题记录下来,帮助那些和我一样的人。

好奇心强,喜欢并深入研究古天文。

崇尚 个人系统创建,做一些时间越长越有价值的事情。思考 把时间留下来 又 每刻都是新的。

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1810042.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

构建高效的数据存储系统:Python dbm 模块的应用与实践

&#x1f340; 前言 博客地址&#xff1a; CSDN&#xff1a;https://blog.csdn.net/powerbiubiu &#x1f44b; 简介 dbm&#xff08;Database Manager&#xff09;是Python中的一个模块&#xff0c;用于创建和管理简单的键值对数据库。它提供了一种简单而有效的方式来存储和…

HTML静态网页成品作业(HTML+CSS)—— 环保主题介绍网页(5个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有5个页面。 二、作品演示 三、代…

hadoop未授权访问命令执行漏洞复现-vulfocus

1 介绍 Hadoop YARN&#xff08;Yet Another Resource Negotiator&#xff09;的ResourceManager是集群资源管理的核心组件&#xff0c;负责分配和管理集群资源以及调度作业。如果ResourceManager出现未授权访问漏洞&#xff0c;可能允许未经认证的用户访问或操作集群资源&…

二叉树顺序结构——堆的结构与实现

二叉树顺序结构——堆的结构与实现 一、二叉树的顺序结构二、堆的概念及结构三、堆的实现堆向下调整算法堆的创建建堆时间复杂度堆的插入(堆向上调整算法)堆的删除堆的代码实现(使用VS2022的C语言)初始化、销毁构建、插入、删除返回堆顶元素、判空、返回有效元素个数 四、完整 …

Python深度学习之PyTorch基础教程

⛄前言 PyTorch是一个基于Torch的Python开源机器学习(深度学习)框架&#xff0c;由Facebook的人工智能研究院开发&#xff0c;不仅能够实现强大的GPU加速&#xff0c;还支持动态神经网络&#xff0c;使得研究人员和开发人员能够轻松构建和训练复杂的深度学习模型。与TensorFlo…

贪心算法 -- 组合一组数字获得最大数

贪心算法 – 组合一组数字获得最大数 文章目录 贪心算法 -- 组合一组数字获得最大数题目重现读懂题目贪心场景代码示例 题目重现 题目链接&#xff1a;最大数 - 力扣 给定一组非负整数 nums&#xff0c;重新排列每个数的顺序&#xff08;每个数不可拆分&#xff09;使之组成一…

error 12154 received logging on to the standby报错处理

错误 处理方法 该参数不是主库的servicename &#xff08;低级错误&#xff09; SQL> alter system set log_archive_dest_2 SERVICEstandby ASYNC VALID_FOR(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAMEstandby; System altered. 观察主库日志: 备库日志: 该问题会影…

Python集合的基本概念和使用方法

目录 集合&#xff08;Set&#xff09; 基本概念 基本特性 基本操作 集合运算 成员测试 高级操作 集合推导式 总结 集合&#xff08;Set&#xff09; Python集合&#xff08;Set&#xff09;是Python语言中一个非常实用且强大的数据结构&#xff0c;它用于存储多个不…

day27回溯算法part03| 39. 组合总和 40.组合总和II 131.分割回文串

39. 组合总和 题目链接/文章讲解 | 视频讲解 本题是 集合里元素可以用无数次&#xff0c;那么和组合问题的差别 其实仅在于 startIndex上的控制 class Solution { public:int sum;vector<int> path;vector<vector<int>> result;void backtracking(vector<…

爬虫工具yt-dlp

yt-dlp是youtube-dlp的一个fork&#xff0c;youtube-dlp曾经也较为活跃&#xff0c;但后来被众多网站屏蔽&#xff0c;于是大家转而在其基础上开发yt-dlp。yt-dlp的github项目地址为&#xff1a;GitHub - yt-dlp/yt-dlp: A feature-rich command-line audio/video downloaderA …

Java学习【深入探索包装类和泛型】

Java学习【深入探索包装类和泛型】 &#x1f680;包装类获取包装类对象的方式使用valueOf()创建直接赋值 Integer成员方法 &#x1f680;泛型引出泛型泛型类泛型方法泛型接口泛型的继承和通配符泛型的上界 在Java的学习中&#xff0c;包装类和泛型是两个重要的概念&#xff0c;…

分布式事务AP控制方案(上)

分布式事务控制方案 本篇文章给出一种要求高可用性&#xff08;AP思想&#xff09;的分布式事务控制方案 下篇新鲜出炉&#xff1a;点我查看 分布式事务控制方案1、业务背景2、本地消息表的设计3、对消息表的操作4、任务调度5、任务流程控制的抽象类6、课程发布的实现类7、总…

我的创作纪念日--我和CSDN一起走过的1825天

机缘 第一次在CSDN写文章&#xff0c;是自己在记录学习Java8新特性中Lambda表达式的内容过程中收获的学习心得。之前也有记录工作和生活中的心得体会、难点的解决办法、bug的排查处理过程等等。一直都用的有道笔记&#xff0c;没有去和大家区分享的想法&#xff0c;是一起的朋…

《Brave New Words 》2.4 与历史对话

Part II: Giving Voice to the Social Sciences 第二部分&#xff1a;为社会科学发声 Conversing with History 与历史对话 Good history and civics teachers make the past interesting. Great history and civics teachers make the past come alive. When history and civi…

作业07 递推算法2

作业&#xff1a; #include <iostream> using namespace std; int main(){int a[110][110]{0},b[110][110]{0},n;cin>>n;for(int i1;i<n;i){for(int j1;j<i;j){cin>>a[i][j];}}for(int in-1;i>1;i--){for(int j1;j<i;j){a[i][j]a[i][j]max(a[i1]…

离散数学--连通性和矩阵

目录 0.关系的运算和性质 1.通路和回路 2.连通关系 3.割点&#xff08;边&#xff09;和点&#xff08;边&#xff09;割集 4.强&#xff08;弱&#xff09;连通&单向连通 0.关系的运算和性质 &#xff08;1&#xff09;这个运算包括了矩阵的运算&#xff0c;包括这个…

汽车数据应用构想(三)

上期说的&#xff0c;用数据去拟合停车信息的应用&#xff0c;那么类似的POI信息相关的场景其实都可以实现。今天讲讲用户使用频率也很高的加油/充电场景。 实际应用中&#xff0c;在加油场景中用户关心的通常还是价格。无论是导航还是各种加油APP/小程序&#xff0c;都已经很…

了解常用智能指针

智能指针 1、概念 C中引入智能指针的主要目的是为了解决内存管理的问题&#xff0c;传统的指针&#xff08;裸指针&#xff09;在使用时需要手动分配和释放内存&#xff0c;容易出现内存泄漏和悬挂指针等问题。智能指针通过封装裸指针&#xff0c;并提供自动内存管理功能&…

端午安康,最真挚的祝福送最“粽”要的人

端午节&#xff0c;又称端阳节、龙舟节、重五节、天中节等&#xff0c;是集拜神祭祖、祈福辟邪、欢庆娱乐及饮食为一体的民俗大节&#xff0c;与春节、清明节、中秋节并称为中国四大传统节日&#xff0c;2008年被列为国家法定节假日&#xff0c;2009年9月端午节成为中国首个入选…