【Spring之底层核心架构概念解析】
文章目录
- 一、BeanDefinition
- 二、BeanDefinitionReader
- 2.1、AnnotatedBeanDefinitionReader
- 2.2、XmlBeanDefinitionReader
- 五、ClassPathBeanDefinitionScanner
- 六、BeanFactory
- 七、ApplicationContext
- 7.1、AnnotationConfigApplicationContext
- 7.2、ClassPathXmlApplicationContext
- 八、类型转换
- 8.1、PropertyEditor
- 8.2、ConversionService
- 8.3、TypeConverter
- 九、FactoryBean
- 十、ExcludeFilter和IncludeFilter
- 十一、MetadataReader、ClassMetadata、AnnotationMetadata
前置准备测试对象User:
public class User {public User(int flag, String uuid){System.out.println(flag+"----------"+uuid);}public User(){System.out.println("User 无参构造");}}
一、BeanDefinition
BeanDefinition表示Bean的定义,其可记录Bean的特征,例如:
- Bean的类型:beanClass属性
- Bean的作用域:Scope属性
- Bean是否为懒加载:lazyinit属性
…
在Spring中,定义一个bean的方式主要有:XML文件中使用bean标签来定义其bean属性,除此外,可以使用@Bean注解以及@Component等注解来定义注解,当然,也可以使用编程式来定义Bean,如下代码:
//Spring核心概念测试类
public class TestSpringDemo {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);//定义一个BeanDefinition对象AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();//向BeanDefinition对象中添加对象信息beanDefinition.setBeanClass(User.class);beanDefinition.setScope("prototype");//将BeanDefinition对象加入到Spring容器中context.registerBeanDefinition("user",beanDefinition);System.out.println("Spring BeanDefinition 创建的user对象为:"+context.getBean("user"));UserService userService = (UserService) context.getBean("userService");userService.test();}
}

二、BeanDefinitionReader
其表示BeanDefinition读取器,主要的读取方式有以下两种
2.1、AnnotatedBeanDefinitionReader
这个组件可以将某各类直接转换为BeanDefinition,并且会解析该类上的注解,测试代码如下:
//Spring核心概念测试类
public class TestSpringDemo {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);//声明一个BeanDefinition读取器,并在这个读取器中传入Spring容器AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(context);annotatedBeanDefinitionReader.register(User.class);System.out.println("BeanDefinition读取器AnnotatedBeanDefinitionReader创建bean为:"+context.getBean("user"));UserService userService = (UserService) context.getBean("userService");userService.test();}
}

2.2、XmlBeanDefinitionReader
该接口主要是通过解析XML文件中的Bean标签进行BeanDefinition转换,代码如下:
XML配置文件信息:

//Spring核心概念测试类
public class TestSpringDemo {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);//声明一个BeanDefinition读取器,并在这个读取器中传入Spring容器XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(context);int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");System.out.println("扫描到bean标签数量:"+i);System.out.println("BeanDefinition读取器XmlBeanDefinitionReader创建bean为:"+context.getBean("user"));UserService userService = (UserService) context.getBean("userService");userService.test();}
}

五、ClassPathBeanDefinitionScanner
其为BeanDefinition资源扫描器,作用和BeanDefinitionReader类似,只是读取的方式是以指定路径的方式扫描类资源,对扫描到的类进行解析,是否包含其相关注解信息,例:如果类中包含@Component注解,就会将该类作为BeanDefinition对象放入到Spring容器中,代码如下:
@Component
public class UserService {public void test(){System.out.println("test--->Spring创建对象");}
}
//Spring核心概念测试类
public class TestSpringDemo {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.refresh();//声明一个BeanDefinition读取器,并在这个读取器中传入Spring容器ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);int scan = scanner.scan("com.practice.service");System.out.println("指定路径下,扫描到的bean资源数量:"+scan);System.out.println("ClassPathBeanDefinitionScanner扫描器创建bean为:"+context.getBean("userService"));}
}

六、BeanFactory
BeanFactory会负责创建Bean,并且提供获取Bean的API
七、ApplicationContext
ApplicationContext是BeanFactory的一种,其在Spring的源码中的定义为:

图中的ListableBeanFactory和HierarchicalBeanFactory都继承至BeanFactory,所以ApplicationContext也是具备BeanFactory具备的特性和功能,但是,ApplicationContext还具备额外的功能,例如,支持国际化、支持获取环境信息、支持事件发布和相关资源加载,其有两个实现类,如下介绍
7.1、AnnotationConfigApplicationContext
其源代码如下:

AnnotationConfigApplicationContext继承了GenericApplicationContext,实现了AnnotationConfigRegistry接口,拥有了其父类以及父接口以及父接口继承甚至更向上的接口所有的功能
7.2、ClassPathXmlApplicationContext

其是继承了AbstractApplicationContext,但是相对于AnnotationConfigApplicationContext而言,功能没有AnnotationConfigApplicationContext强大,比如不能注册BeanDefinition
八、类型转换
在Spring中,有可能会存在一些类型转换的问题,其Spring中提供了一些技术来方便做类型转换操作,在Spring源码中,与存在许多类型转换的操作,类型转化主要有以下接口
8.1、PropertyEditor
这是JDK自带的类型转换工具类,具体使用如下:
public class StringToUserPropertyEditor extends PropertyEditorSupport implements PropertyEditor {@Overridepublic void setAsText(String text) throws IllegalArgumentException {User user = new User();user.setName(text);this.setValue(user);}
}
//Spring核心概念测试类
public class TestSpringDemo {public static void main(String[] args) {StringToUserPropertyEditor propertyEditor = new StringToUserPropertyEditor();propertyEditor.setAsText("1");User value = (User) propertyEditor.getValue();System.out.println(value);}
}

8.2、ConversionService
Spring中提供的类型转化服务,它比PropertyEditor更强大,其代码如下:
public class StringToUserConverter implements ConditionalGenericConverter {@Overridepublic boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {return sourceType.getType().equals(String.class) &&targetType.getType().equals(User.class);}@Overridepublic Set<ConvertiblePair> getConvertibleTypes() {return Collections.singleton(new ConvertiblePair(String.class, User.class));}@Overridepublic Object convert(Object source, TypeDescriptor sourceType, TypeDescriptortargetType) {User user = new User();user.setName((String)source);return user;}
}
//Spring核心概念测试类
public class TestSpringDemo {public static void main(String[] args) {DefaultConversionService conversionService = new DefaultConversionService();conversionService.addConverter(new StringToUserConverter());User value = conversionService.convert("1", User.class);System.out.println(value);}
}

8.3、TypeConverter
整合了PropertyEditor和ConversionService的功能,是Spring内部用的,如下:
//Spring核心概念测试类
public class TestSpringDemo {public static void main(String[] args) {SimpleTypeConverter typeConverter = new SimpleTypeConverter();typeConverter.registerCustomEditor(User.class, new StringToUserPropertyEditor());User value = typeConverter.convertIfNecessary("1", User.class);System.out.println(value);}
}

九、FactoryBean
我们想一个Bean完完全全由我们来创造,可以通过FactoryBean来完成,如下:
public class factoryBeanTest implements FactoryBean {@Overridepublic Object getObject() throws Exception {UserService userService = new UserService();return userService;}@Overridepublic Class<?> getObjectType() {return UserService.class;}}
通过上面这段代码,我们自己创造了一个UserService对象,并且它将成为Bean。但是通过这种方式创造出来的UserService的Bean,只会经过初始化后,其他Spring的生命周期步骤是不会经过的,比如依赖注入
十、ExcludeFilter和IncludeFilter
这两个Filter是Spring扫描过程中用来过滤的。ExcludeFilter表示排除过滤器,IncludeFilter表示包含过滤器,如下:



FilterType分为:
1. ANNOTATION:表示是否包含某个注解
2. ASSIGNABLE_TYPE:表示是否是某个类
3. ASPECTJ:表示否是符合某个Aspectj表达式
4. REGEX:表示是否符合某个正则表达式
5. CUSTOM:自定义
十一、MetadataReader、ClassMetadata、AnnotationMetadata
在Spring中需要去解析类的信息,比如类名、类中的方法、类上的注解,这些都可以称之为类的元数据,所以Spring中对类的元数据做了抽象,并提供了一些工具类
MetadataReader表示类的元数据读取器,默认实现类为SimpleMetadataReader。代码如下示例:
package com.practice.service;import org.springframework.stereotype.Component;@Component
public class UserService {public void test(){System.out.println("test--->Spring创建对象");}
}
//Spring核心概念测试类
public class TestSpringDemo {public static void main(String[] args) throws IOException {SimpleMetadataReaderFactory simpleMetadataReaderFactory = newSimpleMetadataReaderFactory();// 构造一个MetadataReaderMetadataReader metadataReader =simpleMetadataReaderFactory.getMetadataReader("com.practice.service.UserService");// 得到一个ClassMetadata,并获取了类名ClassMetadata classMetadata = metadataReader.getClassMetadata();System.out.println(classMetadata.getClassName());// 获取一个AnnotationMetadata,并获取类上的注解信息AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();for (String annotationType : annotationMetadata.getAnnotationTypes()) {System.out.println(annotationType);}}
}

注:SimpleMetadataReader去解析类时,使用的ASM技术。因为Spring启动的时候需要去扫描,如果指定的包路径比较宽泛,那么扫描的类是非常多的,那如果在Spring启动时就把这些类全部加载进JVM了,这样不太好,所以使用了ASM技术。
相关文章:
【Spring之底层核心架构概念解析】
文章目录 一、BeanDefinition二、BeanDefinitionReader2.1、AnnotatedBeanDefinitionReader2.2、XmlBeanDefinitionReader 五、ClassPathBeanDefinitionScanner六、BeanFactory七、ApplicationContext7.1、AnnotationConfigApplicationContext7.2、ClassPathXmlApplicationCont…...
手把手带你创建一个自己的GPTs
大家好,我是五竹。 最近GPT又进行了大升级,这一下又甩了国内AI几条街,具体更新了哪些内容之前的一篇文章中其实已经说过了:ChatGPT 王炸升级!更强版 GPT-4 上线! 其中最重要的一点就是支持自定义GPT&…...
Vue 组件+es6箭头函数+路由
一、组件 1、让网页或局部页实现复用,包括js(vue)功能 组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素, …...
Clickhouse学习笔记(5)—— ClickHouse 副本
Data Replication | ClickHouse Docs 副本的目的主要是保障数据的高可用性,即使一台 ClickHouse 节点宕机,那么也可以从其他服务器获得相同的数据 注意: clickhouse副本机制的实现要基于zookeeperclickhouse的副本机制只适用于MergeTree f…...
ELMo模型、word2vec、独热编码(one-hot编码)的优缺点进行对比
下面是对ELMo模型、word2vec和独热编码(one-hot编码)的优缺点进行对比: 独热编码(One-hot Encoding): 优点: 简单,易于理解。适用于词汇表较小的场景。 缺点: 高维度…...
FFmpeg简介1
适逢FFmpeg6.1发布,准备深入学习下FFmpeg,将会写下系列学习记录。 在此列出主要学习资料,后续再不列,感谢这些大神的探路和分享,特别是雷神,致敬! 《FFmpeg从入门到精通》 《深入理解FFmpeg》 …...
2352 智能社区医院管理系统JSP【程序源码+文档+调试运行】
摘要 本文介绍了一个智能社区医院管理系统的设计和实现。该系统包括管理员、护工和医生三种用户,具有社区资料管理、药品管理、挂号管理和系统管理等功能。通过数据库设计和界面设计,实现了用户友好的操作体验和数据管理。经过测试和优化,系…...
高教社杯数模竞赛特辑论文篇-2023年B题:多波束测线布设(附获奖论文及MATLAB代码实现)(续)
目录 5.3.3 模拟退火对测线布设仿真检验 5.3.4 开角、坡度的灵敏度分析...
【fast2021论文导读】 Learning Cache Replacement with Cacheus
文章:Learning Cache Replacement with Cacheus 导读摘要: 机器学习的最新进展为解决计算系统中的经典问题开辟了新的、有吸引力的方法。对于存储系统,缓存替换是一个这样的问题,因为它对性能有巨大的影响。 本文第一个贡献,确定了与缓存相关的特征,特别是,四种工作负载…...
在 React 中选择使用 JSX 或 JavaScript
在 React 中选择使用 JSX 或 JavaScript JSX vs. JavaScriptReact Component Lifecycle JSX 是 React 最常用的语法之一,它允许我们在 HTML 中嵌入 JavaScript 语句和表达式。但是,如果我们不需要 JSX 又该怎么办呢?让我们一起来了解一下 J…...
Halcon WPF 开发学习笔记(4):Halcon 锚点坐标打印
文章目录 专栏前言锚点二次开发添加回调函数辅助Model类 下集预告 专栏 Halcon开发 博客专栏 WPF/HALCON机器视觉合集 前言 Halcon控件C#开发是我们必须掌握的,因为只是单纯的引用脚本灵活性过低,我们要拥有Halcon辅助开发的能力 锚点开发是我们常用的…...
【从0到1设计一个网关】性能优化---使用Disruptor提供缓冲区
文章目录 什么是缓冲区队列Disruptor高性能的原因Disruptor实战注:学习这篇文章之前推荐先对Disruptor的使用有了解,否则我的代码中即使有非常详细的注释你也并不能理解这些注释的作用,以及为什么我要需要这样子编写代码。 同时,这将会是网关系列最后一篇文章,由于文章写的…...
Redis 特殊数据类型
目录 1、redis地理空间(GEO) 2、redis基数统计(HyperLogLog) 3、redis位图(bitmap) 4、redis位域bitfield) 5、redis流(Stream) 1、redis地理空间(GEO) Redis 的地理空间数据结构(GEO)可以用于存储地理位置信息,并支持附近位置搜索等功能…...
【Windows网络编程】二.TCP套接字编程与主机上线实验
API: socket: 套接字函数创建绑定到特定传输服务提供程序的套接字。 函数原型:SOCKET WSAAPI socket([in] int af,[in] int type,[in] int protocol );参数: af:地址规范系列: AF_INET:IPv4&…...
Qt 事件循环
引出 UI程序之所叫UI程序,是因为需要与用户有交互,用户交互一般是通过鼠标键盘等的输入设备,那UI程序就需要有能随时响应用户交互的能力。 一个C程序的main函数大概是下面这样: int main() {...return 0; } 我们如何使程序能随…...
【趣味随笔】YOLO的“进化史”极简版(YOLO v1-->YOLOP)
📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨ 📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 📢:文章若有幸对你有帮助,可点赞 👍…...
Leetcode421. 数组中两个数的最大异或值
Every day a Leetcode 题目来源:421. 数组中两个数的最大异或值 解法1:贪心 位运算 初始化答案 ans 0。从最高位 high_bit 开始枚举 i,也就是 max(nums) 的二进制长度减一。设 newAns ans 2i,看能否从数组 nums 中选两个…...
SPRINGBOOT整合CXF发布WEB SERVICE和客户端调用(用户和密码验证)
主要分为客户端和服务端 服务端 pom配置 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.4.3</version><relativePath/> <!-- lookup parent fro…...
代码随想录训练营Day5:哈希数组
算是哈希的容器:数组(适合连续存放);set,map(适合无序存放)。所以数组操作就是hash[i];而set,map.insert(元素),map可以map[]是因为map存放了键值对可以索引查找。关于几个数组相加等…...
UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
