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

news2025/1/18 9:05:25

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

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

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

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

相关文章

Apache IoTDB 分布式架构三部曲(三)副本与共识算法

IoTDB 首创并应用的共识协议统一框架&#xff0c;为用户提供了灵活选择不同共识算法的可能性。 对于一个分布式集群而言&#xff0c;为了使得海量数据场景下集群能够横向扩展&#xff0c;集群需要按照一定的规则将全部数据分成多个子集存储在不同的节点上&#xff0c;从而能够更…

【C/C++】——小白初步了解——内存管理

目录 1. C/C内存分布 代码区&#xff08;Code Segment&#xff09;&#xff1a; 数据区&#xff08;Data Segment&#xff09;&#xff1a; 堆区&#xff08;Heap&#xff09;&#xff1a; 栈区&#xff08;Stack&#xff09;&#xff1a; 常量区&#xff08;Constant Seg…

spring boot 2.1 集成activiti 6.0.0和activiti-modeler 5.23.0可视化编辑器(随记)

先上pom&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.or…

AI高考大战,揭秘五大热门模型谁能问鼎数学之巅?

在高考前&#xff0c;我就有想法了&#xff0c;这一次让AI来做做高考题。就用国内的大模型&#xff0c;看哪家的大模型解题最厉害。 第一天考完&#xff0c;就拿到了2024高考数学2卷的电子版&#xff0c;这也是重庆市采用的高考试卷 这次选了5个AI工具&#xff0c;分别是天工&a…

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

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

hot100 -- 二分查找

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

Vue10-事件修饰符

一、示例&#xff1a;<a>标签不执行默认的跳转行为 1-1、方式一 <a href"http://www.baidu.com" onclick"event.preventDefault();">点击我</a> 1-2、方式二 1-3、方式三&#xff1a;事件修饰符 二、Vue的六种事件修饰符 2-1、prevent&…

Edge怎么关闭快捷键

Edge怎么关闭快捷键 在Edge浏览器中&#xff0c;你可以通过以下步骤关闭快捷键&#xff1a; 打开Edge浏览器&#xff0c;输入&#xff1a;edge://flags 并按下回车键。 在Flags页面中&#xff0c;搜索“快捷键”(Keyboard shortcuts)选项。 将“快捷键”选项的状态设置为“…

注册小程序

每个小程序都需要在 app.js 中调用 App 方法注册小程序实例&#xff0c;绑定生命周期回调函数、错误监听和页面不存在监听函数等。 详细的参数含义和使用请参考 App 参考文档 。 整个小程序只有一个 App 实例&#xff0c;是全部页面共享的。开发者可以通过 getApp 方法获取到全…

HuggingFace团队亲授大模型量化基础: Quantization Fundamentals with Hugging Face

Quantization Fundamentals with Hugging Face 本文是学习https://www.deeplearning.ai/short-courses/quantization-fundamentals-with-hugging-face/ 这门课的学习笔记。 What you’ll learn in this course Generative AI models, like large language models, often exce…

转让无区域商业管理公司挺批行业包变更

无区域的名称我们可以直接进行名称的申请核准。 从新规施行之后&#xff0c;国家局核名批准难度更高。新申请的无区域名称已经停批了&#xff0c;进行核名将更难&#xff0c;而需要满足一定条件并在成立一年后才能变更升级名称。而这个过程并非易事&#xff0c;难度非常高。可以…

45-1 waf绕过 - 文件上传绕过WAF方法

环境准备: 43-5 waf绕过 - 安全狗简介及安装-CSDN博客然后安装dvwa靶场:构建完善的安全渗透测试环境:推荐工具、资源和下载链接_渗透测试靶机下载-CSDN博客打开dvwa靶场,先将靶场的安全等级调低,然后切换到文件上传 一、符号变异 在PHP中,由于其弱类型特性,有时候仅有一…

JavaSE——抽象类和接口

目录 一 .抽象类 1.抽象类概念 2.抽象类语法 3.抽象类特性 4.抽象类的作用 二. 接口 1.接口的概念 2.语法规则 3.接口的使用 4.接口特性 5.实现多个接口 6.接口间的继承 三.抽象类和接口的区别 一 .抽象类 1.抽象类概念 在面向对象的概念中&#xff0c;所有的对…

SpringCloud整合OpenFeign实现微服务间的通信

1. 前言 1.1 为什么要使用OpenFeign&#xff1f; 虽说RestTemplate 对HTTP封装后, 已经⽐直接使⽤HTTPClient简单⽅便很多, 但是还存在⼀些问题. 需要拼接URL, 灵活性⾼, 但是封装臃肿, URL复杂时, 容易出错. 代码可读性差, ⻛格不统⼀。 1.2 介绍一下微服务之间的通信方式 微…

Zabbix实现邮件和钉钉实时告警(使用python脚本)

告警和通知 告警是监控的主要职能,是指将到达某一阈值事件的消息发送给用户,让用户在事件发生的时候即刻知道监控项处于不正常状态,从而让用户来决定是否采取相关措施。 zabbix中,告警是由一系列的流程组成的,⾸首先是触发器到达阈值,接下是Active对事件信息进行处理,其…

TCP/IP协议分析实验:通过一次下载任务抓包分析

TCP/IP协议分析 一、实验简介 本实验主要讲解TCP/IP协议的应用&#xff0c;通过一次下载任务&#xff0c;抓取TCP/IP数据报文&#xff0c;对TCP连接和断开的过程进行分析&#xff0c;查看TCP“三次握手”和“四次挥手”的数据报文&#xff0c;并对其进行简单的分析。 二、实…

ElasticSearch学习笔记之一:介绍及EFK部署

1. 系统概述 The Elastic Stack&#xff0c;包括Elasticsearch、Kibana、Beats和Logstash&#xff08;也成为ELK Stack&#xff09; Elasticsearch&#xff1a;简称ES&#xff0c;是一个开源的高扩展的分布式全文搜索引擎&#xff0c;是整个Elastic Stack技术栈的核心。它可以…

【MySQL】聊聊MySQL常见的SQL语句阻塞场景

在平时的业务中&#xff0c;可能一个简单的SQL语句也执行很慢&#xff0c;这种情况其实大多数都是要么没有使用索引&#xff0c;要么出现锁竞争造成执行阻塞。本篇主要来介绍具体的场景 CREATE TABLE t ( id int(11) NOT NULL, c int(11) DEFAULT NULL, PRIMARY KEY (id) ) ENG…

用HAL库改写江科大的stm32入门-6-4 PWM驱动舵机

接线图&#xff1a; 如何控制一个舵机 舵机的控制由一个脉冲宽度调制信号(PWM波&#xff09;来实现&#xff0c;该信号在这个实验里使用stm32来发出。 舵机通讯协议&#xff1a; 对应设置参数&#xff1a; ARR的值为19999 CCR的值为500~2500(生成占空比是2.5%~12.5%的波形)…

[经验] 昆山教育网(昆山教育网中小学报名) #媒体#职场发展#微信

昆山教育网&#xff08;昆山教育网中小学报名&#xff09; 昆山教育局网站 网站&#xff1a;昆山市教育局 昆山市教育局全面贯彻执行党和国家的教育方针、政策&#xff0c;落实有关教育工作的法律、法规&#xff1b;负责制定本市教育工作的实施意见和措施&#xff0c;并监督…