spring源码解析-(1)关于Bean

什么是Bean?

是spring对所有注入到IoC容器中的类的统称。

我们要注册进入spirng的bean千奇百怪,所以spring必须需要使用一个统一的定义来标识bean,就有了接下来的BeandDefinition,通过名称我们就可以知道,他是对bean的定义。

Spring的BeanDefinition详解

效果:将不同来源的bean进行归一化处理

什么是BeandDefinition? 下面是BeanDefinition的源码,BeanDefinition是一个接口,他继承了两个接口,分别是AttributeAccessor和BeanMetadataElement。

简单来说,spring将所有需要装在到容器中的类进行了归一化处理,他们的共同属性都通过BeanDefinition去约束。

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;int ROLE_APPLICATION = 0;int ROLE_SUPPORT = 1;int ROLE_INFRASTRUCTURE = 2;void setParentName(@Nullable String parentName);@NullableString getParentName();void setBeanClassName(@Nullable String beanClassName);@NullableString getBeanClassName();void setScope(@Nullable String scope);@NullableString getScope();void setLazyInit(boolean lazyInit);boolean isLazyInit();void setDependsOn(@Nullable String... dependsOn);@NullableString[] getDependsOn();void setAutowireCandidate(boolean autowireCandidate);boolean isAutowireCandidate();void setPrimary(boolean primary);boolean isPrimary();void setFactoryBeanName(@Nullable String factoryBeanName);@NullableString getFactoryBeanName();void setFactoryMethodName(@Nullable String factoryMethodName);@NullableString getFactoryMethodName();ConstructorArgumentValues getConstructorArgumentValues();default boolean hasConstructorArgumentValues() {return !getConstructorArgumentValues().isEmpty();}MutablePropertyValues getPropertyValues();default boolean hasPropertyValues() {return !getPropertyValues().isEmpty();}void setInitMethodName(@Nullable String initMethodName);@NullableString getInitMethodName();void setDestroyMethodName(@Nullable String destroyMethodName);@NullableString getDestroyMethodName();void setRole(int role);int getRole();void setDescription(@Nullable String description);@NullableString getDescription();ResolvableType getResolvableType();boolean isSingleton();boolean isPrototype();boolean isAbstract();@NullableString getResourceDescription();@NullableBeanDefinition getOriginatingBeanDefinition();
}

从代码中,我们可以看出,BeanDefinition一共有两种实现类型,一种是AnnotatedBeanDefinition,另一种则是AbstractBeanDefinition。

不难看出,AnnotatedBeanDefinition是对BeanDefinition接口的扩展,而AbstractBeanDefinition是一个抽象方法, 实现了大部分的模板方法,以便子类去使用。

在这里插入图片描述

有了存储类的统一元数据结构,那么spring将需要一种特定的数据结构去存储这些内容,spring提供了这么一个接口BeanDefinitionRegistry,能力如下:

public interface BeanDefinitionRegistry extends AliasRegistry {void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException;void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;boolean containsBeanDefinition(String beanName);String[] getBeanDefinitionNames();int getBeanDefinitionCount();boolean isBeanNameInUse(String beanName);
}

通过BeanDefinitionRegistry中提供的方法中我们可以看到他拥有什么能力,首先将名称和对应的beanDefinition进行匹配。

其次,通过getBeanDefinitionNames,不难看出我们可以一个beandefinition可以拥有多个别名。

可以通过BeanDefinitionRegistry的实现类来窥探spring究竟是如何存储的,其实很简单,是通过一个map进行存储的。

具体代码如下:

public class SimpleBeanDefinitionRegistry extends SimpleAliasRegistry implements BeanDefinitionRegistry {private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(64);@Overridepublic void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {Assert.hasText(beanName, "'beanName' must not be empty");Assert.notNull(beanDefinition, "BeanDefinition must not be null");this.beanDefinitionMap.put(beanName, beanDefinition);}@Overridepublic void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {if (this.beanDefinitionMap.remove(beanName) == null) {throw new NoSuchBeanDefinitionException(beanName);}}@Overridepublic BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {BeanDefinition bd = this.beanDefinitionMap.get(beanName);if (bd == null) {throw new NoSuchBeanDefinitionException(beanName);}return bd;}@Overridepublic boolean containsBeanDefinition(String beanName) {return this.beanDefinitionMap.containsKey(beanName);}@Overridepublic String[] getBeanDefinitionNames() {return StringUtils.toStringArray(this.beanDefinitionMap.keySet());}@Overridepublic int getBeanDefinitionCount() {return this.beanDefinitionMap.size();}@Overridepublic boolean isBeanNameInUse(String beanName) {return isAlias(beanName) || containsBeanDefinition(beanName);}
}

通过registerBeanDefinition方法可以看出,将beanName与beanDefinition进行绑定,多个beanName可以绑定同一个beanDefinition。

怎样去使用BeanDefinition的实现类呢?

首先创建一个实体类:

@Component // 后面测试注解的方式用到的
public class Person {private Integer id;private String name;public Person() {}public Person(Integer id, String name) {this.id = id;this.name = name;}@Overridepublic String toString() {return "Person{" +"id=" + id +", name='" + name + '\'' +'}';}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

1、通过读取xml中的数据

xml代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="person" class="com.test.entity.Person"><property name="id" value="1"/><property name="name" value="不会敲代码的吕小桥"/></bean></beans>

测试类:

BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
BeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
reader.loadBeanDefinitions("test.xml");
System.out.println(registry.getBeanDefinitionCount());

输出内容:

> Task :spring-test:BeanDefinitionTest.main()
1

2、通过注解的方式读取bean

注意:Person类需要加上Component注解

测试方法

BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(registry);
reader.register(Person.class);
System.out.println(registry.getBeanDefinitionNames());

输出如下:

org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
person
org.springframework.context.event.internalEventListenerFactory
org.springframework.context.annotation.internalAutowiredAnnotationProcessor

3、通过包扫描的方式读取bean

测试方法:

// 扫描指定包下的所有类
BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
// 扫描指定包下的所有类
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
scanner.scan("com.test.entity");
for (String beanDefinitionName : registry.getBeanDefinitionNames()) {System.err.println(beanDefinitionName);
}

输出结果:

org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
person
org.springframework.context.event.internalEventListenerFactory
org.springframework.context.annotation.internalAutowiredAnnotationProcessor

思考总结:

1、在查看源码的过程中,发现源码中有很多地方用到了如下代码:

Assert.hasText(beanName, "'beanName' must not be empty");

以上代码可以有效的避免我们在开发中大量的if判断,同时可以让你的代码可阅读性更高。

hutools和spring依赖中均有该类型的写法,可以参考一下。

2、设计模式&接口&抽象类,帮助更好的处理一系列方法

在面对一系列处理的时候,我们应该抽象出接口,并使用抽象类去约定模板方法,继而使用子类去实现,这种方式会节省我们大量重复的工作,而且所有的方法都有迹可循,在模板方法中定义流程,在子类中实现,能够有效的解耦流程和实现。这样我们就可以只关心子类的具体实现了。

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

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

相关文章

美国演员工会SAG-AFTRA 要求人工智能在广告中使用演员声音需征得同意并付费

SAG-AFTRA 的新豁免允许在人工智能生成的广告中使用演员的声音&#xff0c;但需要同意、补偿和安全措施 美国演员工会&#xff08;SAG-AFTRA&#xff09;推出了一项新的豁免&#xff0c;以保护会员免受未经授权的人工智能在广告中使用其声音的影响。动态人工智能音频广告豁免定…

C语言Kruskal算法求最小生成树

Kruskal算法求出最小生成树。 图形 算法描述 先找最小权值边为1的边有&#xff08;V1&#xff0c;V4&#xff09;&#xff0c;&#xff08;V2&#xff0c;V9&#xff09;&#xff0c;保证不产生回路就可以成功选择边 除去上一次找的边后&#xff0c;在找权值最小的边为2的有&a…

制作AI问答机器人:从0到1的完整指南

在数字化转型的浪潮中&#xff0c;企业正追求更高效、智能的客户服务解决方案。AI问答机器人以其快速响应、全天候服务和持续学习的能力&#xff0c;成为了提升客户满意度和加速业务发展的关键工具。本文将深入探讨如何制作一个企业级的AI问答机器人&#xff0c;并强调其功能体…

OpenAI发表研究论文 介绍了一种逆向工程AI模型工作原理的方法

ChatGPT 开发商 OpenAI 构建人工智能的方法本周遭到了前员工的抨击&#xff0c;他们指责该公司利用可能有害的技术冒不必要的风险。今天&#xff0c;OpenAI 发布了一篇新的研究论文&#xff0c;目的显然是为了表明它在通过提高模型的可解释性来应对人工智能风险方面的认真态度。…

hot100 -- 二分查找

目录 前言 &#x1f382;搜索插入位置 &#x1f33c;搜索二维矩阵 &#x1f33c;排序数组元素第一和最后一个位置 &#x1f33c;旋转排序数组 &#x1f4aa;旋转排序数组中的最小值 &#x1f4aa;两个正序数组的中位数 前言 二分算法学习_时间超限ac:0%-CSDN博客 &#…

2024年【起重机械指挥】考试及起重机械指挥新版试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 起重机械指挥考试考前必练&#xff01;安全生产模拟考试一点通每个月更新起重机械指挥新版试题题目及答案&#xff01;多做几遍&#xff0c;其实通过起重机械指挥试题及解析很简单。 1、【多选题】《中华人民共和国特…

【Androi】安卓发展历程详解

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

git推送代码到github拒绝推送的解决方案

这里描述一下本地推送的场景&#xff0c;首先我在码云上建立了一个前端项目&#xff0c;进行了自己的个性化开发&#xff0c;后期在github上创建了一个一样的项目仓库存放代码。使用webstorm进行代码开发。在下面这个位置可以选择推送的代码位置。 选择推送github仓库之后&…

Python深度学习基于Tensorflow(16)基于Tensorflow的对话实例

文章目录 基础数据清洗数据生成词汇表定义分词器并制作数据集构建Transformer模型并训练模型推理 Tensorflow 的核心就是注意力机制&#xff0c;在之前详细的介绍过&#xff0c;具体可以看这个&#xff1a;Python深度学习基于Tensorflow&#xff08;9&#xff09;注意力机制_te…

什么情况下需要配戴助听器

以下几种情况需要考虑配戴助听器&#xff1a; 1、听力无波动3个月以上的感音神经性听力障碍。如:先天性听力障碍、老年性听力障碍、噪声性听力障碍、突聋的稳定期等&#xff0c;均可选配合适的助听器。 2、年龄方面。使用助听器没有严格的年龄限制&#xff0c;从出生数周的婴…

深度学习Week16——数据增强

文章目录 深度学习Week16——数据增强 一、前言 二、我的环境 三、前期工作 1、配置环境 2、导入数据 2.1 加载数据 2.2 配置数据集 2.3 数据可视化 四、数据增强 五、增强方式 1、将其嵌入model中 2、在Dataset数据集中进行数据增强 六、训练模型 七、自定义增强函数 一、前言…

Geoserver源码解读一(环境搭建)

一、Github地址 https://github.com/geoserver/geoserver 1.1 克隆代码 git clone https://github.com/geoserver/geoserver.git 1.2 选择版本 版本选择参考我的上一篇文章 Geoserver 以及 Geotools各版本和jdk版本对照表 此处我选择的是兼容jdk8的最后一个版本 git che…

netty+springboot+vue聊天室(需要了解netty)

先看看这个使用websocket实现的聊天室&#xff0c;因为前端是使用websocket&#xff0c;和下面的demo的前端差不多就不解释实现原理&#xff0c;所以建议还是看看(要是会websocket的大佬请忽略) springbootwebsocketvue聊天室 目录 一、实现内容二、代码实现1.后端2.前端源码…

html+CSS+js部分基础运用17

在图书列表中&#xff0c;为书名“零基础学JavaScript”和“HTML5CSS3精彩编程200例”添加颜色。&#xff08;请用class或style属性实现&#xff09;&#xff0c;效果如下图1所示&#xff1a; 图1 图书列表 Class和style的综合应用。&#xff08;1&#xff09;应用class的对象、…

命令行打包最简单的android项目从零开始到最终apk文件

准备好需要的工具 AndroidDevTools - Android开发工具 Android SDK下载 Android Studio下载 Gradle下载 SDK Tools下载 jdk的链接我就不发出来,自己选择,我接下来用的是8版本的jdk和android10的sdk sdk的安装和环境变量的配置 sdk tool压缩包打开后是这样子,打开sdk mana…

高防CDN是如何应对DDoS和CC攻击的

高防CDN&#xff08;内容分发网络&#xff09;主要通过分布式的网络架构来帮助网站抵御DDoS&#xff08;分布式拒绝服务&#xff09;和CC&#xff08;挑战碰撞&#xff09;攻击。 下面是高防CDN如何应对这些攻击的详细描述&#xff1a; 1. DDoS攻击防护 DDoS攻击通过大量的恶…

【动态规划-BM71 最长上升子序列(一)】

题目 BM71 最长上升子序列(一) 分析 dp[i] 考虑到下标i&#xff0c;其组成的最长上升子序列长度 可以用动态规划的原因&#xff1a; 到i的结果可以由到j &#xff08;j<i) 的结果推出&#xff0c;只需要判断下标j对应的数字是否比下标i 对应的字母小即可 注意&#xf…

vs2013 - 打包

文章目录 vs2013 - 打包概述installshield2013limitededitionMicrosoft Visual Studio 2013 Installer Projects选择哪种来打包? 笔记VS2013打包和VS2019打包的区别打包工程选择view打包工程中单击工程名称节点&#xff0c;就可以在属性框中看到要改的属性(e.g. 默认是x86, 要…

Linux安装RocketMQ教程【带图文命令巨详细】

巨详细Linux安装Nacos教程RocketMQ教程 1、检查残留版本2、上传压缩包至服务器2.1压缩包获取2.2创建相关目录 3、安装RocketMQ4、配置RocketMQ4.1修改runserver.sh和runbroker.sh启动脚本4.2新增broker.conf配置信息4.3启动关闭rocketmq4.4配置开机自启动&#xff08;扩展项&am…

AI Agentic Design Patterns with AutoGen(下):工具使用、代码编写、多代理群聊

文章目录 四、工具使用: 国际象棋游戏4.1 准备工具4.2 创建两个棋手代理和棋盘代理4.3 注册工具到代理4.4 创建对话流程&#xff0c;开始对话4.5 增加趣味性&#xff1a;加入闲聊 五、代码编写&#xff1a;财务分析5.1导入和配置代码执行器5.2 创建 代码执行/编写 代理5.3 定义…