spring 源码阅读之@Configuration解析
@Configuration解析
@Configuration注解用于标识一个类是配置类,用于声明和组织Bean定义,首先@Configuration本身也是一个@Component,在其注解定义上标有@Component
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {}
通常使用配置类作为参数传递给AnnotationContext,
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(EnvConfig.class);
然后将该类作为一个bean进行初始化,AnnotationConfigApplicationContext在实例化的时候会调用
AnnotationConfigUtils#registerAnnotationConfigProcessors注册必要的bean处理器,这里就会注册一个与解析Configuration相关的类:ConfigurationClassPostProcessor
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
ConfigurationClassPostProcessor 实现了BeanDefinitionRegistryPostProcessor,是一个bean定义后置处理器。在sprnig 的容器refresh方法里有一步操作
invokeBeanFactoryPostProcessors(beanFactory);
这里会拿出所有的BeanDefinitionRegistryPostProcessor进行调用其postProcessBeanDefinitionRegistry(registry)方法。这一步发生在bean实例化之前用于扩展beanDef。
ConfigurationClassPostProcessor
后置处理方法会调用postProcessBeanDefinitionRegistry。然后拿出所有的beanDef寻找@Configuration标识的bean。
判断是否是配置bean方法ConfigurationClassUtils#checkConfigurationClassCandidate
public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {String className = beanDef.getBeanClassName();AnnotationMetadata metadata;if (beanDef instanceof AnnotatedBeanDefinition &&className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {// Can reuse the pre-parsed metadata from the given BeanDefinition...metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();}else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {// Check already loaded Class if present...//这几个类型的跳过Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||BeanPostProcessor.class.isAssignableFrom(beanClass) ||AopInfrastructureBean.class.isAssignableFrom(beanClass) ||EventListenerFactory.class.isAssignableFrom(beanClass)) {return false;}metadata = AnnotationMetadata.introspect(beanClass);}else {//获取metadataMetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);metadata = metadataReader.getAnnotationMetadata();}//解读Configuration注解配置,config能解到证明是一个配置beanMap<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);}else if (config != null || isConfigurationCandidate(metadata)) {beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);}else {return false;}// It's a full or lite configuration candidate... Let's determine the order value, if any.Integer order = getOrder(metadata);if (order != null) {beanDef.setAttribute(ORDER_ATTRIBUTE, order);}return true;
}
然后解析的到的配置bean会经过ConfigurationClassParser类进行配置解析,具体解析方法在processConfigurationClass,真正解析方法doProcessConfigurationClass
1、PropertySource解析
//获取PropertySource注解
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class,org.springframework.context.annotation.PropertySource.class)) {if (this.environment instanceof ConfigurableEnvironment) {processPropertySource(propertySource);//解析配置文件}else {logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +"]. Reason: Environment must implement ConfigurableEnvironment");}
}
可以在配置bean类上通过@PropertySource注解进行properties配置文件的加载。
@PropertySource("classpath:a.properties")
也可以通过@PropertySources加载多个文件.
2、ComponentScan解析
ComponentScan可以定义扫描bean的包路径,这里spring容器会根据ComponentScan配置的包路径取寻找@Component标注的bean。
@ComponentScan(basePackages = {"com.test.service"})
解析源码
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {for (AnnotationAttributes componentScan : componentScans) {// The config class is annotated with @ComponentScan -> perform the scan immediately//会调用scanner.doScan方法进行bean定义的发现Set<BeanDefinitionHolder> scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());// Check the set of scanned definitions for any further config classes and parse recursively if neededfor (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();if (bdCand == null) {bdCand = holder.getBeanDefinition();}if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {parse(bdCand.getBeanClassName(), holder.getBeanName());}}}
}
3、解析@Import
//getImports方法获取@Import注解引入的类
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
这里判断import的bean是否是ImportSelector、ImportBeanDefinitionRegistrar进行不同的处理,如果都不是安默认按照是一个配置bean进行解析。
4、解析@ImportResource
这个注解主要是引入xml配置进行解析
5、解析方法bean
配置bean里可以通过方法上@Bean注解进行bean的定义
@Bean
public EnvService envService(){EnvService service = new EnvService();return service;
}
通过retrieveBeanMethodMetadata方法获取方法上有@Bean注解的进行解析。
上面解析的几个步骤解析结果会包装成一个ConfigurationClass,然后通过ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsFromImportedResources方法将beandef加载到beanFacotry中。这里ComponentScan注解不会走这里,在scan过程中已完成。
相关文章:
spring 源码阅读之@Configuration解析
Configuration解析 Configuration注解用于标识一个类是配置类,用于声明和组织Bean定义,首先Configuration本身也是一个Component,在其注解定义上标有Component Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) Documented Co…...
Java Web 33道面试题汇总
更多面试合集在:https://javaxiaobear.cn 1、http 的长连接和短连接? HTTP 协议有 HTTP/1.0 版本和 HTTP/1.1 版本。HTTP1.1 默认保持长连接(HTTP persistent connection,也翻译为持久连接),数据传输完成了保持 TCP 连接不断开(不发 RST 包、不四次握手),等待在同域名…...
设计模式记录
设计模式 抽象工厂模式单例模式要实现一个单例,需要关注的点有下面几个: 抽象工厂模式 PHP工厂模式是一种可扩展、可维护和可重复使用的方法,旨在提供通用接口,用于创建对象。工厂模式的主要组成部分包括抽象工厂、具体工厂、抽象产品和具体产…...
Java设计模式之亨元模式(Flyweight Pattern)
亨元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享对象来最大限度地减少内存使用和提高性能。该模式适用于需要创建大量相似对象的情况,其中许多对象具有相同的状态。通过共享相同的状态,亨元模式可以减少…...
正点原子嵌入式linux驱动开发——Linux中断
不管是单片机裸机实验还是Linux下的驱动实验,中断都是频繁使用的功能,在裸机中使用中断需要做一大堆的工作,比如配置寄存器,使能IRQ等等。但是Linux内核提供了完善的中断框架,只需要申请中断,然后注册中断处…...
基于Jaya优化算法的电力系统最优潮流研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
Write-Ahead Log(PostgreSQL 14 Internals翻译版)
日志 如果发生停电、操作系统错误或数据库服务器崩溃等故障,RAM中的所有内容都将丢失;只有写入磁盘的数据才会被保留。要在故障后启动服务器,必须恢复数据一致性。如果磁盘本身已损坏,则必须通过备份恢复来解决相同的问题。 理论…...
CUDA 学习记录
1.关于volatile: 对于文章中这个函数, __global__ void reduceUnrollWarps8 (int *g_idata, int *g_odata, unsigned int n) {// set thread IDunsigned int tid threadIdx.x;unsigned int idx blockIdx.x * blockDim.x * 8 threadIdx.x;// convert…...
【Java 进阶篇】深入了解 Bootstrap 按钮和图标
按钮和图标在网页设计中扮演着重要的角色,它们是用户与网站或应用程序交互的关键元素之一。Bootstrap 是一个流行的前端框架,提供了丰富的按钮样式和图标库,使开发者能够轻松创建吸引人的界面。在本文中,我们将深入探讨 Bootstrap…...
基于Java的人事管理系统设计与实现(源码+lw+部署文档+讲解等)
文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding) 代码参考数据库参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…...
代码随想录算法训练营第五十九天| 647. 回文子串 516.最长回文子序列
今日学习的文章链接和视频链接 回文子串 https://programmercarl.com/0647.%E5%9B%9E%E6%96%87%E5%AD%90%E4%B8%B2.html 516.最长回文子序列 https://programmercarl.com/0516.%E6%9C%80%E9%95%BF%E5%9B%9E%E6%96%87%E5%AD%90%E5%BA%8F%E5%88%97.html 动态规划总结篇 https:…...
uniapp 小程序优惠劵样式
先看效果图 上代码 <view class"coupon"><view class"tickets" v-for"(item,index) in 10" :key"item"><view class"l-tickets"><view class"name">10元优惠劵</view><view cl…...
元梦之星内测上线,如何在B站打响声量?
元梦之星是腾讯天美工作室群研发的超开星乐园派对手游,于2023年1月17日通过审批。该游戏风格可爱软萌,带有社交属性,又是一款开黑聚会的手游,备受年轻人关注。 飞瓜数据(B站版)显示,元梦之星在…...
Python---循环---while循环
Python中的循环 包括 while循环与for循环,本文以while循环为主。 Python中所有的知识点,都是为了解决某个问题诞生的,就好比中文的汉字,每个汉字都是为了解决某种意思表达而诞生的。 1、什么是循环 现实生活中,也有…...
面试知识点--基础篇
文章目录 前言一、排序1. 冒泡排序2. 选择排序3. 插入排序4. 快速单边循环排序5. 快速双边循环排序6. 二分查找 二、集合1.List2.Map 前言 提示:以下是本篇文章正文内容,下面案例可供参考 一、排序 1. 冒泡排序 冒泡排序就是把小的元素往前调或者把大…...
FIFO设计16*8,verilog,源码和视频
名称:FIFO设计16*8,数据显示在数码管 软件:Quartus 语言:Verilog 代码功能: 使用verilog语言设计一个16*8的FIFO,深度16,宽度为8。可对FIFO进行写和读,并将FIFO读出的数据显示到…...
#力扣:2769. 找出最大的可达成数字@FDDLC
2769. 找出最大的可达成数字 - 力扣(LeetCode) 一、Java class Solution {public int theMaximumAchievableX(int num, int t) {return num 2*t;} }...
Juniper防火墙SSG-140 session 过高问题
1.SSG-140性能参数 2.问题截图 3.解决方法 (1)通过telnet 或 consol的方法登录到防火墙; (2)使用get session 查看总的session会话数,如果大于300 一般属于不正常情况 (3)使用get…...
Spring Boot 3.2四个新特点提升运行性能
随着 Spring Framework 6.1 和 Spring Boot 3.2 普遍可用性的临近,我们想分享一下 Spring 团队为让开发人员优化其应用程序的运行时效率而做出的几项努力的概述。 我们将介绍以下技术和用例: Spring MVC 将使用 基于JDK 21 虚拟线程 Web 堆栈使用 Spri…...
一阶系统阶跃响应实现规划方波目标值
一阶系统单位阶跃响应 一阶系统传递函数,实质是一阶惯性环节,T为一阶系统时间常数。 输入信号为单位阶跃函数,数学表达式 单位阶跃函数拉氏变换 输出一阶系统单位阶跃响应 拉普拉斯反变换 使用前向差分法对一阶系统离散化 将z变换写成差分方…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...
消防一体化安全管控平台:构建消防“一张图”和APP统一管理
在城市的某个角落,一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延,滚滚浓烟弥漫开来,周围群众的生命财产安全受到严重威胁。就在这千钧一发之际,消防救援队伍迅速行动,而豪越科技消防一体化安全管控平台构建的消防“…...
全面解析数据库:从基础概念到前沿应用
在数字化时代,数据已成为企业和社会发展的核心资产,而数据库作为存储、管理和处理数据的关键工具,在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理,到社交网络的用户数据存储,再到金融行业的交易记录处理&a…...
若依登录用户名和密码加密
/*** 获取公钥:前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...
SQL进阶之旅 Day 22:批处理与游标优化
【SQL进阶之旅 Day 22】批处理与游标优化 文章简述(300字左右) 在数据库开发中,面对大量数据的处理任务时,单条SQL语句往往无法满足性能需求。本篇文章聚焦“批处理与游标优化”,深入探讨如何通过批量操作和游标技术提…...
