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);
	@Nullable
	String getParentName();
	void setBeanClassName(@Nullable String beanClassName);
	@Nullable
	String getBeanClassName();
	void setScope(@Nullable String scope);
	@Nullable
	String getScope();
	void setLazyInit(boolean lazyInit);
	boolean isLazyInit();
	void setDependsOn(@Nullable String... dependsOn);
	@Nullable
	String[] getDependsOn();
	void setAutowireCandidate(boolean autowireCandidate);
	boolean isAutowireCandidate();
	void setPrimary(boolean primary);
	boolean isPrimary();
	void setFactoryBeanName(@Nullable String factoryBeanName);
	@Nullable
	String getFactoryBeanName();
	void setFactoryMethodName(@Nullable String factoryMethodName);
	@Nullable
	String getFactoryMethodName();
	ConstructorArgumentValues getConstructorArgumentValues();
	default boolean hasConstructorArgumentValues() {
		return !getConstructorArgumentValues().isEmpty();
	}
	MutablePropertyValues getPropertyValues();
	default boolean hasPropertyValues() {
		return !getPropertyValues().isEmpty();
	}
	void setInitMethodName(@Nullable String initMethodName);
	@Nullable
	String getInitMethodName();
	void setDestroyMethodName(@Nullable String destroyMethodName);
	@Nullable
	String getDestroyMethodName();
	void setRole(int role);
	int getRole();
	void setDescription(@Nullable String description);
	@Nullable
	String getDescription();
	ResolvableType getResolvableType();
	boolean isSingleton();
	boolean isPrototype();
	boolean isAbstract();
	@Nullable
	String getResourceDescription();
	@Nullable
	BeanDefinition 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);
	@Override
	public 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);
	}
	@Override
	public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
		if (this.beanDefinitionMap.remove(beanName) == null) {
			throw new NoSuchBeanDefinitionException(beanName);
		}
	}
	@Override
	public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
		BeanDefinition bd = this.beanDefinitionMap.get(beanName);
		if (bd == null) {
			throw new NoSuchBeanDefinitionException(beanName);
		}
		return bd;
	}
	@Override
	public boolean containsBeanDefinition(String beanName) {
		return this.beanDefinitionMap.containsKey(beanName);
	}
	@Override
	public String[] getBeanDefinitionNames() {
		return StringUtils.toStringArray(this.beanDefinitionMap.keySet());
	}
	@Override
	public int getBeanDefinitionCount() {
		return this.beanDefinitionMap.size();
	}
	@Override
	public 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;
	}

	@Override
	public 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、设计模式&接口&抽象类,帮助更好的处理一系列方法

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IEDA 默认依赖概述

IEDA 默认依赖概述 目录概述需求&#xff1a; 设计思路实现思路分析1.AI Azure OpenAlAzure Al SearchAmazon BedrockChroma Vector DatabaseMilvus Vector DatabaseMistral AlNeo4J Vector DatabaseOllamaOpenAlPGvector Vector DatabasePinecone Vector DatabasePostgresMLRe…

IM即时通信技术

本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl IM&#xff0c;即Instant Messaging&#xff0c;是指即时通讯技术&#xff0c;它允许用户通过互联网实时交换文本、语音、视频、文件等多种形式的信息。这种技术打破了传统通信方式的时…

MySQL提权之UDF提权

1、前言 最近遇到udf提权&#xff0c;几经周折终于搞懂了。感觉挺有意思的&#xff0c;渗透思路一下子就被打开了。 2、什么是udf提权 udf 全称为user defined function&#xff0c;意思是用户自定义函数。用户可以对数据库所使用的函数进行一个扩展&#xff08;windows利用…

[office] 如何在Excel中拉动单元格时表头不变形- #学习方法#职场发展#经验分享

如何在Excel中拉动单元格时表头不变形? 如何在Excel中拉动单元格时表头不变形&#xff1f;Excel是我们常用的办公软件&#xff0c;当我们使用Excel拉动单元格时表头不变形&#xff0c;该如何操作呢&#xff0c;下面小编就为大家做详细讲解 如何在Excel中拉动单元格时表头不变…

Vue02-搭建Vue的开发环境

一、Vue.js的安装 1-1、直接用 <script> 引入&#xff08;CDN&#xff09; 1、CDN的说明 2、Vue的版本说明 生产版本是开发版本的压缩。 3、Vue的引入 验证是否存在Vue函数&#xff1a; 4、搭建Vue的开发环境 ①、下载开发版本的Vue&#xff0c;并在代码中引入 ②、安…

【Linux】系统优化:一键切换软件源与安装Docker

引言 在Linux系统安装完成后&#xff0c;进行一些必要的初始化设置是提升系统性能和用户体验的关键。本文将重点介绍两个实用的一键脚本&#xff1a;LinuxMirrors提供的软件源切换脚本和Docker安装脚本。这两个脚本将帮助我们简化配置安装过程。 一键切换软件源脚本 在Linux…

AB测试实战

AB测试实战 1、AB测试介绍&#x1f43e; 很多网站/APP的首页都会挂一张头图(Banner)&#xff0c;用来展示重要信息&#xff0c;头图是否吸引人会对公司的营收带来重大影响&#xff0c;一家寿险公司Humana设计了如下三张头图&#xff0c;现在需要决定使用哪一张放到首页&#x…

Java——JVM

前言 JVM.即Java虚拟机.用来解释执行Java字节码. 一、JVM中的内存区域划分 JVM其实也是一个进程,进程运行过程中,要从操作系统这里申请一些资源(内存就是其中的典型资源) 这些内存空间,就支撑了后续Java程序的执行. JVM从系统中申请了一大块内存,这一大块内存给Java程序使…

TOGAF数字化转型的关键(文尾附在线TOGAF免费测试)

业务架构驱动数据架构和应用架构的设计&#xff0c;而应用架构又依赖于数据架构和技术架构的支持。技术架构则为整个架构提供了稳定的基础设施。 在数字化转型中&#xff0c;协调和整合这四种架构是至关重要的。通过确保它们之间的一致性和协同工作&#xff0c;可以实现企业业务…

高效文件传输攻略:利用局域网共享实现极速数据同步

最近&#xff0c;我换了一台新电脑&#xff0c;面对两个电脑之间文件备份和传输的问题&#xff0c;感到十分头疼。经过多方了解&#xff0c;我发现可以在原电脑上设置共享文件&#xff0c;然后接收方从共享文件中接受即可&#xff0c;这样可以将局域网的带宽拉满&#xff0c;比…

力扣78. 子集

给你一个整数数组nums&#xff0c;数组中的元素互不相同。返回该数组所有可能的子集&#xff08;幂集&#xff09;。解集不能包含重复的子集。你可以按任意顺序返回解集。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[],[1],[2],[1,2],[3],[1,3…

GIS数据快捷共享发布工具及操作视频

有网友反映还是不会操作GIS数据快捷共享发布工具&#xff08;建立自己的地图网站&#xff09;&#xff0c;要我录个视频。 好&#xff0c;那就录一个: GIS数据快捷共享发布工具及操作视频 虽然默认例子是二维的&#xff0c;但这个服务器可以为二维、三维系统发布时间服务。都是…

AI炒股:用kimi获取美股实时行情数据并保存到Excel

在kimi中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个编写Python脚本的任务&#xff0c;具体步骤如下&#xff1a; 获取美股实时美股行情数据&#xff0c;然后保存在F盘的Excel文件中&#xff0c;Excel文件名为&#xff1a;usstock20240605.xlsx 实…

物联网实战--平台篇之(十三)物模型设备端

本项目的交流QQ群:701889554 物联网实战--入门篇https://blog.csdn.net/ypp240124016/category_12609773.html 物联网实战--驱动篇https://blog.csdn.net/ypp240124016/category_12631333.html 物联网实战--平台篇https://blog.csdn.net/ypp240124016/category_12653350.htm…

存在d盘里的数据突然没有了?别担心,恢复方案在此

在数字化时代&#xff0c;数据存储的重要性不言而喻。然而&#xff0c;有时候我们会遭遇一些意想不到的困扰&#xff0c;比如存储在D盘的数据突然消失。这不仅可能导致重要文件的丢失&#xff0c;还可能影响我们的工作和生活。本文将探讨D盘数据消失的可能原因&#xff0c;提供…

【机器学习】与【数据挖掘】技术下【C++】驱动的【嵌入式】智能系统优化

目录 一、嵌入式系统简介 二、C在嵌入式系统中的优势 三、机器学习在嵌入式系统中的挑战 四、C实现机器学习模型的基本步骤 五、实例分析&#xff1a;使用C在嵌入式系统中实现手写数字识别 1. 数据准备 2. 模型训练与压缩 3. 模型部署 六、优化与分析 1. 模型优化 模…

OpenAI新研究破解GPT-4大脑,分解1600万个特征打开“黑匣子”,Ilya 、Jan Leike也参与了!

6月7日凌晨&#xff0c;OpenAI在官网发布了一个新的研究成果&#xff0c;首次破解GPT-4的神经网络活动。通过改进大规模训练稀疏自动编码器将GPT-4的内部表示分解为 1600 万个特征。而且&#xff0c;前段时间离职的Ilya Sutskever、Jan Leike也是作者之一&#xff01; 这不是破…

【CS.SE】浅谈: 程序员的职业素养与成长之路

文章目录 1 引言2 持续学习与自我提升2.1 永无止境的学习之路2.2 真实案例&#xff1a;自学Python 3 团队合作与沟通能力3.1 高效沟通是团队成功的基石 4 责任心与职业道德4.1 责任心&#xff1a;代码背后的承诺4.2 真实案例&#xff1a;修复紧急Bug 5 适应变化与快速反应5.1 适…

pytorch 自定义学习率更新 Poly

Poly 学习率调整策略需要继承_LRScheduler类&#xff0c;该类包含三个重要属性和两个重要方法 学习率与batch-size的关系 一般来说&#xff0c;batch-size的大小一般与学习率的大小成正比。batch-size越大一般意味着算法收敛方向的置信度越大&#xff0c;也可以选择较大的学…

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

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