[源码系列:手写spring] IOC第十三节:Bean作用域,增加prototype的支持

news2025/4/8 20:57:55

         为了帮助大家更深入的理解bean的作用域,特意将BeanDefinition的双例支持留到本章节中,创建Bean,相关Reader读取等逻辑都有所改动。

内容介绍

        在Spring中,Bean的作用域(Scope)定义了Bean的生命周期和可见性。包括单例和原型,在本章节中我们将为Bean添加多例的支持,下面是Prototype作用域的几个特征介绍:

1. 多例(Prototype): Bean的prototype作用域表示每次从容器中获取该Bean时都会创建一个新的实例。每个请求或依赖注入都会导致创建一个全新的Bean对象。

2. 不受Spring容器管理: prototype作用域的Bean实例不受Spring容器的管理,容器在创建Bean之后不会再跟踪它。这意味着Spring容器不会负责释放或销毁prototype作用域的Bean。一旦Bean被创建并交给调用者,调用者负责Bean的生命周期,包括销毁。

3. 适用场景: prototype作用域适用于那些每次获取实例时都需要全新状态的Bean,例如,HTTP请求的处理器或线程池中的任务。这样可以确保每次获取的Bean都是独立的,不会影响其他实例。

        这里设计到设计模式中的原型模式,形象地说,可以将prototype作用域的Bean比喻为一个不断复制的模具。每次你需要一个新的Bean实例时,Spring容器会根据模具再次制作一个全新的Bean。这个模具本身不受容器管理,而是由你自己管理它的生命周期。这与singleton作用域的Bean不同,后者是像一个单一的实例化对象,由容器管理其生命周期。
 

当前bean生命周期
prototype作用域

        可见prototype类型的bean并不受spring容器的管理,你需要自己负责销毁或释放这些Bean实例,以防止内存泄漏。 

代码分支

GitHub - yihuiaa/little-spring: 剖析Spring源码,包括常见特性IOC、AOP、三级缓存等...剖析Spring源码,包括常见特性IOC、AOP、三级缓存等... Contribute to yihuiaa/little-spring development by creating an account on GitHub.icon-default.png?t=N7T8https://github.com/yihuiaa/little-spring

核心代码

 BeanDefinition

    private String scope = SCOPE_SINGLETON;
    private boolean singleton = true;
    private boolean prototype = false;
    public static String SCOPE_SINGLETON = "singleton";
    public static String SCOPE_PROTOTYPE = "prototype";

    public void setScope(String scope) {
        this.scope = scope;
        this.singleton = SCOPE_SINGLETON.equals(scope);
        this.prototype = SCOPE_PROTOTYPE.equals(scope);
    }

    public boolean isSingleton() {
        return this.singleton;
    }
    public boolean isPrototype() {
        return this.prototype;
    }

AbstractAutowireCapableBeanFactory#doCreateBean()

...	
	protected Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
		Object bean = null;
		try {
			bean = createBeanInstance(beanDefinition);
			//为bean填充属性
			applyPropertyValues(beanName, bean, beanDefinition);
			//执行bean的初始化方法和BeanPostProcessor的前置和后置处理方法
			initializeBean(beanName, bean, beanDefinition);
		} catch (Exception e) {
			throw new BeansException("Instantiation of bean failed", e);
		}

		//注册有销毁方法的bean
		registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);

		if (beanDefinition.isSingleton()) {
			addSingleton(beanName, bean);
		}
		return bean;
	}
...

AbstractAutowireCapableBeanFactory#registerDisposableBeanIfNecessary()

	/**
	 * 注册有销毁方法的bean,即bean继承自DisposableBean或有自定义的销毁方法
	 *
	 * @param beanName
	 * @param bean
	 * @param beanDefinition
	 */
	protected void registerDisposableBeanIfNecessary(String beanName, Object bean, BeanDefinition beanDefinition) {
		//只有singleton类型bean会执行销毁方法
		if (beanDefinition.isSingleton()) {
			if (bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())) {
				registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, beanDefinition));
			}
		}
	}

测试

prototype-bean.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
	         http://www.springframework.org/schema/beans/spring-beans.xsd
		 http://www.springframework.org/schema/context
		 http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <bean id="car" class="bean.Car" scope="prototype">
        <property name="name" value="Rolls-Royce"/>
    </bean>

</beans>

单元测试

public class PrototypeBeanTest {
	@Test
	public void testPrototype() throws Exception {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:prototype-bean.xml");

		Car car1 = applicationContext.getBean("car", Car.class);
		Car car2 = applicationContext.getBean("car", Car.class);
		System.out.println(car1 == car2);;
	}
}

测试结果

false
Process finished with exit code 0

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

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

相关文章

【redis进阶】基础知识简要回顾

1. 常见功能介绍 聚合统计 使用list集合的差集、并集来统计 排序统计 SortedSet&#xff08;ZSet&#xff09;统计&#xff0c;再利用分页列出权重高的元素 二值状态统计 BitMap存储&#xff0c;获取并统计 SETBIT uid:sign:3000:202008 2 1 GETBIT uid:sign:3000:202008 2…

Linux动态链接懒加载

Linux动态链接懒加载 懒加载 最近一个名词——懒加载&#xff0c;是一种与动态链接相关的技术&#xff0c;我对它有点感兴趣&#xff0c;于是决定深入了解一番。 懒加载是一种延迟加载资源的策略&#xff0c;它将资源的加载推迟到在首次访问或需要时才执行。这意味着在应用程…

Paper: 利用RNN来提取恶意软件家族的API调用模式

论文 摘要 恶意软件家族分类是预测恶意软件特征的好方法&#xff0c;因为属于同一家族的恶意软件往往有相似的行为特征恶意软件检测或分类方法分静态分析和动态分析两种&#xff1a; 静态分析基于恶意软件中包含的特定签名进行分析&#xff0c;优点是分析的范围覆盖了整个代码…

【Unity3D】UI Toolkit自定义元素

1 前言 UI Toolkit 支持通过继承 VisualElement 实现自定义元素&#xff0c;便于通过脚本控制元素。另外&#xff0c;UI Toolkit 也支持将一个容器及其所有子元素作为一个模板&#xff0c;便于通过脚本复制模板。 如果读者对 UI Toolkit 不是太了解&#xff0c;可以参考以下内容…

《AI辞职信一键生成》告别凡俗套路,展现独特个性!

在这个科技日新月异的时代&#xff0c;我们的生活被各种应用软件深深地渗透。其中&#xff0c;讯飞星火AI大模型的应用无疑是一种创新和突破。最近&#xff0c;我有幸体验了一款名为《AI辞职信一键生成》的web应用&#xff0c;它以其独特的功能和出色的用户体验&#xff0c;让我…

微信小程序Day2笔记

1、WXML模板语法 1. 数据绑定 数据绑定的基本原则 在data中定义数据在WXML中使用数据 2. 在data中定义页面的数据 在页面对应的.js文件中&#xff0c;把数据定义到data对象中。 3. Mustache语法的格式 把data中的数据绑定到页面中渲染&#xff0c;使用Mustache语法&…

不推介使用裸指针的几种情况

情况一&#xff1a; //原生指针没有所有权 void f() {// 不好: 原生指针拥有了所有权int* p1 new int{7}; // ... }template<typename T> class X {public:T* p; // 不好: 不清楚 p 所有权T* q; // 不好: 不清楚 q 所有权// ... };// 不好: 不清楚返回值所有权 Gadget*…

机器学习:自然语言处理上的对抗式攻击

Attacks in NLP 相关话题 Introduction 以前的攻击专注于图像和语音上&#xff0c;而NLP上的内容比较少。而NLP的复杂度跟词典有关系&#xff1a; NLP只能在embedding后的特征上加噪声 Evasion Attacks 电影的评论情感分类&#xff0c;将film换成films后&#xff0c;评论从…

637. 二叉树的层平均值

637. 二叉树的层平均值 题目-简单难度示例1. bfs 题目-简单难度 给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。 示例 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&…

DQN模型

1. DQN模型 References [1] 强化学习第五节&#xff08;DQN&#xff09;【个人知识分享】_哔哩哔哩_bilibili

在MDK-Keil中开发S32K144

对于NXP的S32K1xx系列MCU&#xff0c;前面已经介绍过&#xff0c;官方有专门支持该系列MCU开发的IDE工具——S32DS&#xff0c;这个工具还有对应的代码生成配置工具&#xff0c;而且也是官方推荐使用的工具。 S32DS开发环境是基于Eclipse改写的&#xff0c;熟悉Eclipse的话可以…

python使用百度AipOCR来实现图像文字识别

上篇文字讲到了可以截屏手机模拟器上的界面并传回电脑上&#xff0c;文章链接 python将手机模拟器截屏并发送至电脑上_小小爬虾的博客-CSDN博客 传回来以后&#xff0c;就可以识别出图片中的文字内容了。 我使用的是Python3.10.4&#xff0b;百度的AipOCR库实现图像文字识别…

利用Scrum敏捷工具管理敏捷产品迭代Sprint Backlog

​什么是Sprint Backlog&#xff1f; Sprint Backlog是Scrum的主要工件之一。在Scrum中&#xff0c;团队按照迭代的方式工作&#xff0c;每个迭代称为一个Sprint。在Sprint开始之前&#xff0c;PO会准备好产品Backlog&#xff0c;准备好的产品Backlog应该是经过梳理、估算和优…

systemserver的inputdispatcher直接产生CANCEL事件原理分析-讨厌的android触摸面试题

背景回顾&#xff1a; 上一个blog已经重点讲解了app层面自己产生的Cancel触摸事件&#xff0c;大概产生的原理如下&#xff1a; 上一个blog地址&#xff1a;https://blog.csdn.net/learnframework/article/details/124086882 即可以看出来&#xff0c;在服务端systemserver其实…

国家信息中心举办“数字政府建设暨数字安全技术”研讨会:海云安提出数字政府软件供应链安全解决方案

近日&#xff0c;由国家信息中心主办&#xff0c;复旦大学研究院承办的“数字政府建设暨数字安全技术研讨会”在义乌顺利召开。国家信息中心信息与网络安全部副主任禄凯&#xff0c;复旦大学党委常委、宣传部部长陈玉刚&#xff0c;义乌市委常委、常务副市长喻新贵为会议致辞。…

三、C#—变量,表达式,运算符(3)

&#x1f33b;&#x1f33b; 目录 一、变量1.1 变量1.2 使用变量的步骤1.3 变量的声明1.4 变量的命名规则1.5 变量的初始化1.6 变量初始化的三种方法1.7 变量的作用域1.8 变量使用实例1.9 变量常见错误 二、C#数据类型2.1 数据类型2.2 值类型2.2.1 值类型直接存储值2.2.2 简单类…

【rust/egui】(十)使用painter绘制一些图形—connections

说在前面 rust新手&#xff0c;egui没啥找到啥教程&#xff0c;这里自己记录下学习过程环境&#xff1a;windows11 22H2rust版本&#xff1a;rustc 1.71.1egui版本&#xff1a;0.22.0eframe版本&#xff1a;0.22.0上一篇&#xff1a;这里 绘制连接 在上一节我们使用painter绘制…

《深度学习初探:使用TensorFlow和Keras构建你的第一个神经网络》

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

GCP之Google Cloud Infrastructure

Google Cloud 的物理网络是如何连接的&#xff1f; Google Cloud 分为 regions&#xff0c;regions 又分为 zones。 region 是一个地理区域&#xff0c;其中一个 VM 到另一个 VM 的往返时间 &#xff08;RTT&#xff09; 通常小于 1毫秒&#xff1b;zone 是 region 中的部署区…