《系列二》-- 2、bean 的作用域: Scope 有哪些
阅读之前要注意的东西:本文就是主打流水账式的源码阅读,主导的是一个参考,主要内容需要看官自己去源码中验证。全系列文章基于 spring 源码 5.x 版本。
写在开始前的话:
阅读spring 源码实在是一件庞大的工作,不说全部内容,单就最基本核心部分包含的东西就需要很长时间去消化了:
- beans
- core
- context
实际上我在博客里贴出来的还只是一部分内容,更多的内容,我放在了个人,fork自 spring 官方源码仓了; 而且对源码的学习,必须是要跟着实际代码层层递进的,不然只是干巴巴的文字味同嚼蜡。
这个仓设置的公共仓,可以直接拉取。
作用域 Scope 特性概述
Spring 容器支持以下6种 scopes
常规作用域
在常规的 spring IOC 场景下使用
- prototype: 原型模式
跟单例模式相反,每次使用beanName 向spring 容器申请bean的时候,必须重新new一个bean对象。
如下案例,向spring 容器中注入一个 "原型模式" 作用域的bean, 每次当需要注入 WorkerService 时,都会创建一个全新的bean 对象。
@Component
@Scope("prototype")
public class WorkerService {
public void handler(String arg) {
this.workerDo();
}
public void workerDo() {
// xx 业务逻辑
}
}
- singleton:单例模式<Spring默认的bean作用域>
当用户通过getBean(beanName) 向容器主动申请bean时、或者由 spring 容器自身进行依赖注入操作时;必须保证被当作依赖,注入的单例bean全局唯一。
如下案例:通过注解的方式向容器中注入一个单例bean, spring 容器在第一次创建 UserService 这个bean后会将其缓存下来。
后续通过同样的beanName 来获取这个bean的时候,Spring 容器会将之前缓存的bean引用返回,从而保证 UserService 的bean 全局唯一。
@Component
@Scope("singleton")
public class UserService {
@Autowired
private WorkerService workerService;
public void handler(String arg) {
workerService.handler(arg);
System.out.println("workerService实例对象内存地址:" + workerService);
}
}
web 场景作用域
request: 该作用域的bean,在每次HTTP 请求发生时被创建,它生命周期被,该HTTP请求的生命周期包含。(只有一个bean实例)
session: session作用域的bean,在session的生命周期内有效。(只有一个bean实例)
application: 该作用域的bean 在 ServletContext 的生命周期内有效。(只有一个bean实例)
webSocket: 在webSocket生命周期内有效。(只有一个bean实例)
实际上当下 Spring Web MVC 已经显现颓势,大势已经转向了前后端分离,所以 Web 场景的 bean 作用域的使用场景已经越来越少,本文也不再详细展开。
经典问题
单例作用域的 UserService 中注入,原型作用域的 WorkerService;必须保证从 spring 容器中多次获取 UserService 时,其中注入的 WorkerService 每次都必须不一样。
模拟场景
结合上边讲解单例和原型作用域时,给的伪代码,已知:
UserService 是单例作用域
- WorkerService 将作为依赖注入到 UserService 中
WorkerService 是原型作用域
看如下的程序1和程序2,如果我们从不同的地方,多次使用 UserService.handler(arg), 你猜猜打印出来的 WorkerService 对象地址会是怎样的?
程序1:
@Controller
public class BusinessOld {
@Autowired
private UserService userService;
public void execute(String arg) {
userService.handler("arg");
}
}
程序2:
@Controller
public class BusinessNew {
@Autowired
private UserService userService;
public void execute(String arg) {
userService.handler("arg");
}
}
实际上运行上述的两段代码,输出的 workerService 对象内存地址将会一样. 前边也讲过了spring 对单例bean的管理模式:
单例bean 在第一次被加载后,会被直接缓存在容器中,后续再向容器请求这个单例 bean时,会将之前加载好的bean 直接返回
再说直白点,在UserService 类的单例bean 在第一次被初始化时,其上注入的 WorkerService 类对象就已经注入成功了,由于在UserService 是通过单例的形式注入容器的。
所以它只会被初始化一次,所以 WorkerService 也只会被注入 UserService 中一次。自然就会打印一模一样的 WorkerService 地址了
所以,上述的 程序1 和 程序2 将会输出同样的 WorkerService 对象地址。
解决办法
方法一
借助前边讲过的 "lookup-method"实现
简单回归下这个标签的作用,lookup-method.name 属性配置一个方法名, lookup-method.bean 配置一个beanId;
当从容器中加载 id="lookUpTest" 的bean 时,就会通过 lookup-method.name 配置的方法,动态的返回一个 userBean。
这里我们就不用xml的方式书写案例了,基于上述的原理,我们可以简单改一下 UserService 类的代码:
这里在 UserService.handler() 方法上加了一个注解:@Lookup 这代表着,UserService.handler() 方法每次执行时都会重新向容器获取 WorkerService 类的bean。
因为其以原型模式作用域注入容器,故此可以保证每次都能获取到一个新new出来的 WorkerService 类对象。
@Component
@Scope("singleton")
public class UserService {
@Autowired
private WorkerService workerService;
@Lookup("workerService")
public void handler(String arg) {
workerService.handler(arg);
System.out.println("workerService实例对象内存地址:" + workerService);
}
}
方法二 实现接口 BeanFactoryAware
我们首先看看这个接口的结构:
- 很简单,这里只有一个简单的Setter 方法,从这里可以接收到的参数是 BeanFactory 对象,也就是spring容器工厂本身,意思就是说我把整个车床斗给你了,你还车不出来一个珠子?
既然都拿到工厂了,你要什么bean 还不是随你喜欢,还要啥自行车。下边直接看修改好的代码:
@Component
@Scope("singleton")
public class UserService implements BeanFactoryAware {
private BeanFactory beanFactory; // 接收Setter 注入的容器对象工厂
@Override
public void setBeanFactory(Beanfactory beanFactory) {
this.beanFactory = beanFactory;
}
// @Autowired
// private WorkerService workerService;
@Lookup("workerService")
public void handler(String arg) {
// workerService.handler(arg);
WorkerService workerService = beanFactory.getBean("workerService");
workerService.handler(arg);
System.out.println("workerService实例对象内存地址:" + workerService);
}
}
这里相当于我们会在运行时动态从 BeanFactory 中获取bean: "workerService"
由于我们在bean 定义时把它的作用域定义为了 "原型模式", 故此这里当然可以从容器中捞出单例的 WorkerService
《系列二》-- 2、bean 的作用域: Scope 有哪些的更多相关文章
- Bean的作用域scope
Bean的作用域scope 1.singleton 单例,指一个bean容器中只存在一份 2.prototype 每次请求(每次使用)创建新的实例,destroy方式不生效 3.request 每次h ...
- spring之bean的作用域scope的值的详解
今天研究了一下scope的作用域.默认是单例模式,即 scope="singleton".另外scope还有prototype.request.session.global ses ...
- Spring系列四:Bean Scopes作用域
等闲识得东风面,万紫千红总是春. 概述 在Spring框架中,我们可以在六个内置的spring bean作用域中创建bean,还可以定义bean范围.在这六个范围中,只有在使用支持Web的applic ...
- Spring系列8:bean的作用域
本文内容 bean定义信息的意义 介绍6种bean的作用域 bean定义信息的意义 Spring中区分下类.类定义信息,类实例对象的概念?不容易理解,以餐馆中点炒饭为例. 类: 相当于你看到菜单上炒饭 ...
- Spring学习记录(五)---bean的作用域scope
作用域:singleton:单例,整个应用中只创建一个实例(默认) prototype:原型,每次注入时都新建一个实例 session:会话,每个会话创建一个实例 request:请求,每个请求创建一 ...
- (三)Spring 高级装配 bean的作用域@Scope
1.默认情况下,spring通过@Autowared注入的bean是单例的bean,但有些情况是不满足的,例如:购物车,每个会话,或每个用户登录使用的购物车都是独立的 spring的定义的作用域: a ...
- Spring中bean的作用域scope详解
参考文献:http://blog.csdn.net/jacklearntech/article/details/40157861 http://www.cnblogs.com/qq78292959/p ...
- Spring初学之bean之间的关系和bean的作用域
一.bean之间的关系 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="h ...
- Spring源码系列(二)--bean组件的源码分析
简介 spring-bean 组件是 Spring IoC 的核心,我们可以使用它的 beanFactory 来获取所需的对象,对象的实例化.属性装配和初始化等都可以交给 spring 来管理. 本文 ...
- 【Spring】IoC容器 - Spring Bean作用域Scope(含SpringCloud中的RefreshScope )
前言 上一章学习了[依赖来源],本章主要讨论SpringBean的作用域,我们这里讨论的Bean的作用域,很大程度都是默认只讨论依赖来源为[Spring BeanDefinition]的作用域,因为在 ...
随机推荐
- [转帖]Linux内存管理(一)——从硬件角度看内存管理
从硬件角度看内存管理 ①.在操作系统还没有出来之前,程序都是被存放在卡片上,计算机读取一张卡片就运行一条指令.这种从外部存储介质上直接运行指令的方法效率很低 ②.单道编程的内存管理 所谓单道,就是整个 ...
- [转帖]PG Exporter
http://v0.pigsty.cc/zh/docs/reference/kernel-optimize/ Exporter https://github.com/Vonng/pg_exporter ...
- ebpf的简单学习
ebpf的简单学习-万事开头难 前言 bpf 值得是巴克利包过滤器 他的核心思想是在内核态增加一个可编程的虚拟机. 可以在用户态定义很多规则, 然后直接在内核态进行过滤和使用. 他的效率极高. 因为避 ...
- Nacos集群启动注意事项
简介 Nacos是阿里巴巴开源的一套服务注册发现的应用 使用简单灵活, 是spring Cloud Alibaba的组成部分 现在拆分微服务的部署情况下,极大的需求nacos服务作为支撑 单点情况下存 ...
- Oracle表数量对数据泵备份恢复速度的影响情况
Oracle表数量对数据泵备份恢复速度的影响情况 背景 随着公司产品交付后的时间越来越久. 数据库的备份恢复速度会越来越慢. 最开始一直认为是因为数据量导致的. 但是最近发现, 如果只是将数据库表的量 ...
- 你还在“垃圾”调优?快来看看JDK17的ZGC如何解放双手 | 京东云技术团队
1.前言 不要犹豫了,GC最大停顿时间小于1ms,支持16TB内存,这么高的性能提升,也不需要复杂的调优,节省了这个时间,你去陪对象不香嘛. 上篇文章给大家带来了JDK11升级JDK17的最全实践,相 ...
- 如何写出高质量的代码 data 组件 函数 注释 命名 变量的次数
今天在将以前文件上传的地方全部 改为新的文件上传的api. 在改动的过程中,发现代码有很多不合理的地方 在改的时候,因此也是非常的痛苦的哈. 比如说在data中我有太多的flag标识.俩控制元素的显示 ...
- 如何减缓vm中慢插入的次数
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 偶然发现vm-storage的监控里有这样一个指标:vm_ ...
- 【NSSCTF-Round#16】 Web和Crypto详细完整WP
每天都要加油哦! ------2024-01-18 11:16:55 [NSSRound#16 Basic]RCE但是没有完全RCE <?php error_reporting(0); ...
- Unity Editor自定义菜单排序(MenuItem Order)
扩展Unity的菜单MenuItem MenuItem 属性用于向主菜单和检视面板上下文菜单添加菜单项. 该 MenuItem 属性能够将任何静态函数转变为菜单命令,仅静态函数可使用 MenuItem ...