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

你好,我是柳岸花开。

大家好,今天我们来深入探讨一下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.mzph.cn/diannao/26005.shtml

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

相关文章

红黑树/红黑树迭代器封装(C++)

本篇将会较为全面的讲解有关红黑树的特点&#xff0c;插入操作&#xff0c;然后使用代码模拟实现红黑树&#xff0c;同时还会封装出红黑树的迭代器。 在 STL 库中的 set 和 map 都是使用红黑树封装的&#xff0c;在前文中我们讲解了 AVL树&#xff0c;对于红黑树和 AVL 树来说&…

k8s 1.28 搭建rabbitmq集群

1.环境 1.1 k8s 1.28 1.2 rabbit 3.8 1.3 工作空间default 1.4 注意&#xff0c;内存最好充足一点&#xff0c;因为我就两个节点一个master、一个node&#xff0c;起初我的node是8g&#xff0c;还剩3~4G&#xff0c;集群竟然一直起不来&#xff0c;后来将虚拟机内存扩大&#x…

Word中插入Mathtype右编号,调整公式与编号的位置

当你已经将mathtype内置于word后&#xff0c;可以使用右编号快速插入公式 但是往往会出现公式和编号出现的位置或之间的距离不合适 比如我在双栏下插入公式&#xff0c;会发现插入的公式与编号是适用于单栏的 解决办法&#xff1a; 开始->样式->MTDisplayLquation -&g…

AWT常用组件

AWT中常用组件 前言一、基本组件组件名标签(Label类)Label类的构造方法注意要点 按钮(Button)Button的构造方法注意要点 文本框(TextField)TextField类的构造方法注意要点 文本域&#xff08;TextArea&#xff09;TextArea 的构造方法参数scrollbars的静态常量值 复选框&#x…

排序-读取数据流并实时返回中位数

目录 一、问题描述 二、解题思路 1.顺序表排序法 2.使用大根堆、小根堆 三、代码实现 1.顺序表排序法实现 2.大根堆、小根堆法实现 四、刷题链接 一、问题描述 二、解题思路 1.顺序表排序法 &#xff08;1&#xff09;每次读取一个数就对列表排一次序&#xff0c;对排…

Python异步爬虫批量下载图片-协程

import aiofiles import aiohttp import asyncio import requests from lxml import etree from aiohttp import TCPConnectorclass Spider:def __init__(self, value):# 起始urlself.start_url value# 下载单个图片staticmethodasync def download_one(url):name url[0].spl…

Redis 5种常用数据类型

目录 Redis简介 1.字符串 string 2.哈希 hash 3.列表 list 4.集合 set 5.有序集合 sorted set / zset Redis简介 Redis&#xff0c;全称Remote Dictionary Server&#xff0c;是一个开源的、内存中的数据结构存储系统。它可以用作数据库、缓存和消息中间件&#xff0c;支…

JavaScript前端技术入门教程

引言 在前端开发的广阔天地中&#xff0c;JavaScript无疑是最耀眼的一颗明星。它赋予了网页动态交互的能力&#xff0c;让网页从静态的文本和图片展示&#xff0c;进化为可以与用户进行实时交互的丰富应用。本文将带您走进JavaScript的世界&#xff0c;为您提供一个入门级的教…

SpringBoot3+Mybatis-Plus+h2数据库,入门Mybatis-Plus

SpringBoot3Mybatis-Plush2数据库&#xff0c;入门Mybatis-Plus mybatis-plus官网地址maven依赖数据库脚本配置文件实体类Mapper入门程序启动程序测试单元测试测试结果 Service层接口service层接口单元测试测试结果 项目结构 mybatis-plus官网地址 https://www.baomidou.com/ …

风能远程管理ARMxy嵌入式系统深度解析

智能技术正以前所未有的速度融入传统能源管理体系&#xff0c;而ARMxy工业计算机作为这一变革中的关键技术载体&#xff0c;正以其独特的性能优势&#xff0c;为能源管理的智能化升级铺设道路。本文将聚焦于智能电表、太阳能电站监控、风力发电站远程管理三大应用场景&#xff…

【2023】LitCTF

LitCTF2023&#xff08;复现&#xff09; Web&#xff1a; 1、我Flag呢&#xff1f; ​ ctrlu 读取源码&#xff0c;在最后发现了flag&#xff1a; <!--flag is here flagNSSCTF{3d5218b9-4e24-4d61-9c15-68f8789e8c48} -->2、PHP是世界上最好的语言&#xff01;&…

SQL159 每个创作者每月的涨粉率及截止当前的总粉丝量

描述 用户-视频互动表tb_user_video_log iduidvideo_idstart_timeend_timeif_followif_likeif_retweetcomment_id110120012021-09-01 10:00:002021-09-01 10:00:20011NULL210520022021-09-10 11:00:002021-09-10 11:00:30101NULL310120012021-10-01 10:00:002021-10-01 10:00…

RAG检索与生成的融合

1、rag定义 检索增强生成 (RAG) 模型代表了检索系统和生成模型两大不同但互补组件完美结合的杰作。通过无缝整合相关信息检索和生成与背景相关的响应&#xff0c;RAG模型在人工智能领域达到了前所未有的复杂程度。 2、rag工作流程 2.1、rag整体框架 query通过llm处理后&…

3.haproxy负载均衡

haproxy负载均衡 一、haproxy介绍1、负载均衡类型 二、haproxy配置文件1、backend2、frontend 三、haproxy实现MySQL负载均衡 —— 4层1、后端两台MySQL配置双主复制2、安装配置haproxy2.1 安装软件2.2 编辑配置2.3 启动haproxy2.4 测试通过haproxy正常连接MySQL 四、haproxy实…

张大哥笔记:从古至今,赚钱最快的路子就一个,从未改变

从古至今&#xff0c;赚钱最快的路子就一个&#xff0c;而且从未改变&#xff0c;那就是信息差&#xff01; 不要误解信息差为某种高端复杂的概念&#xff1b;其本质很简单——它就是"你知道而别人不知道的信息"。 曾经我也认为&#xff0c;随着互联网的发展&#x…

Android.基本用法学习笔记

设置文本的内容 先在strings.xml声明变量 方法1. 方法2. 设置文本的大小 1.单位dp&#xff0c;大家可以去学一下有关的单位换算 2. 设置文本颜色 1. 2. 4.设置文本背景颜色 1. 2. 设置视图的宽高 与上级视图一致&#xff0c;也就是上一级有多宽就有多少 1. 2. 3. 4. 设置视图…

【全网最简单的解决办法】vscode中点击运行出现仅当从 VS 开发人员命令提示符处运行 VS Code 时,cl.exe 生成和调试才可用

首先确保你是否下载好了gcc编译器&#xff01;&#xff01;&#xff01; 检测方法&#xff1a; winR 打开cmd命令窗 输入where gcc(如果出现路径则说明gcc配置好啦&#xff01;) where gcc 然后打开我们的vscode 把这个文件删除掉 再次点击运行代码&#xff0c;第一个出现…

【C语言】C语言—通讯录管理系统(源码)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

AI日报0610 -- Prompt这样改,AI成本瞬降20%!

全球首届人工智能选美大赛 世界 AI 创作者大赛和创作者平台 FanVue 正在举办首届“Miss AI”大赛 超过 1,500 名 AI 生成的模特竞逐。这些模型不仅形象逼真 还展示了不同的个性和原因。 评委将评估技术和吸引观众的能力。 奖金池高达 20,000 美元&#xff0c;并有机会参加公关…

【python】python化妆品销售logistic逻辑回归预测分析可视化(源码+课程论文+数据集)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…