IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring 中 BeanDefinition 的注册 -> 正文阅读

[Java知识库]Spring 中 BeanDefinition 的注册

本文我们来了解下 springBeanDefinition 的注册

spring 中对 bean 的注册主要有两种方式:

  • 第一种是通过配置来注册我们的bean,对应的方法是 DefaultListableBeanFactory 里的 registerBeanDefinition() 方法
  • 第二种是直接注册一个单例 bean,对应的方法则是 DefaultListableBeanFactory 里的 registerSingleton() 方法

下面我们分别来看看这两个方法

registerBeanDefinition()

首先是我们的 registerBeanDefinition() 方法

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
		throws BeanDefinitionStoreException {
	/* 对 beanDefinition 进行校验 */
	((AbstractBeanDefinition) beanDefinition).validate();
	
	/* 首先去 map 中(也可以理解为缓存)去查找 beanDefinition */
	BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
	/* 如果找到的 beanDefinition 不为空 */
	if (existingDefinition != null) {
		/* 这里做了一堆判断,如果都没发生错误(异常)就执行下面语句,重新将它放入到map(缓存)中 */
		this.beanDefinitionMap.put(beanName, beanDefinition);
	}
	/* 为空的情况 */
	else {
		/* 将其放入到map中,并将该beanDefinition的名字加入到数组(有序)中 */
		this.beanDefinitionMap.put(beanName, beanDefinition);
		this.beanDefinitionNames.add(beanName);
		/* 跟依赖循环相关的缓存,这里暂时先不关注 */
		removeManualSingletonName(beanName);
		/* 冻结配置相关的代码 */
		this.frozenBeanDefinitionNames = null;
	}
}

registerBeanDefinition() 中,主要逻辑比较简单明了:

  • 首先对 beanDefinition 进行校验
  • 校验通过后先查询缓存
  • 如果缓存中有,则把它覆盖到缓存中
  • 如果缓存中没有,将它注册并加入到缓存中,同时将它的名字也加入到数组(有序的,保存着 beanDefinition 的名字)中

registerSingleton()

第二个方法则是直接向beanFactory中注册一个单例bean

@Override
public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
	/* 执行到这里后,进入下面的方法 */
	super.registerSingleton(beanName, singletonObject);
	updateManualSingletonNames(set -> set.add(beanName), set -> !this.beanDefinitionMap.containsKey(beanName));
	clearByTypeCache();
}
@Override
public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
	/* 这里加锁,保证了注册单例bean时的线程安全 */
	synchronized (this.singletonObjects) {
		/* 从缓存中查询 */
		Object oldObject = this.singletonObjects.get(beanName);
		/* 如果查询到对象不为空(也就是说已经存在该bean),抛出一个异常 */
		if (oldObject != null) {
			throw new IllegalStateException("Could not register object [" + singletonObject +
					"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
		}
		/* 将其加入到 beanFactory 和缓存中 */
		addSingleton(beanName, singletonObject);
	}
}

registerSingleton() 的逻辑就更加简单了:

  • 当执行到 super.registerSingleton(beanName, singletonObject); 这行代码时,调用父类的 registerSingleton() 方法
  • 在父类的 registerSingleton() 方法,首先是判断该 bean 是否已经存在,如果存在的话就向外抛异常,若不存在就将它注册并加入到缓存中

getBean() 的简单介绍

当我们的 beanDefinition 注册完后,该如何去找它们?

依赖查找一般情况下会调用 getBean() 方法

getBean() 方法中会调用 doGetBean() 方法

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
		@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

	final String beanName = transformedBeanName(name);
	Object bean;

	/* 首先去查询 singleton 对象 */
	Object sharedInstance = getSingleton(beanName);
	/* 如果查到对象不为空 */
	if (sharedInstance != null && args == null) {
		/* 将其复制给bean,然后返回 */
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}
	/* 如果查到对象为空(单例 bean 中不存在该 bean,去 BeanDefinition 里面去找) */
	else {
		/*
		 * 这里我们不对里面的细节探讨,只是简单说明以下流程
		 * 如果找到该 beanDefinition,将它变成 bean,并激活其生命周期
		 * 然后返回
		 */
	}
	return (T) bean;
}

我们大概能看出,我们在 getBean() 操作时,会有以下几个步骤

  • 先去查找 Singleton bean ,如果找到则直接返回
  • 若找不到,则去 BeanDefinition 中找,如果找到则将它变成 bean 对象,激活其生命周期,然后返回

总结

本文只是对 beanDefinition 注册相关的一些简单的分析,其中值得关注的是两种 bean 的注册方式:通过配置 bean 和直接注册 singleton bean,还有就是对 bean 的查找的简单分析:先去查单例 bean,找到可以直接返回,找不到的话再去查 BeanDefinition, 若找到了,则直接将其变成 bean,同时激活其生命周期,然后返回。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-07-14 10:44:42  更:2021-07-14 10:45:04 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/17 20:41:34-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码