【Spring】Bean详细解析

1.Spring Bean的生命周期

  • 整体上可以简单分为四步:实例化 —> 属性赋值 —> 初始化 —> 销毁。
  • 初始化这一步涉及到的步骤比较多,包含 Aware 接口的依赖注入、BeanPostProcessor 在初始化前后的处理以及 InitializingBeaninit-method 的初始化操作。
  • 销毁这一步会注册相关销毁回调接口,最后通过DisposableBeandestory-method 进行销毁。

2.Bean是线程安全的吗?

Spring 框架中的 Bean 是否线程安全,取决于其作用域和状态。

我们这里以最常用的两种作用域 prototype 和 singleton 为例介绍。几乎所有场景的 Bean 作用域都是使用默认的 singleton ,重点关注 singleton 作用域即可。

  • prototype 作用域下,每次获取都会创建一个新的 bean 实例,不存在资源竞争问题,所以不存在线程安全问题。
  • singleton 作用域下,IoC 容器中只有唯一的 bean 实例,可能会存在资源竞争问题(取决于 Bean 是否有状态)。如果这个 bean 是有状态的话,那就存在线程安全问题(有状态 Bean 是指包含可变的成员变量的对象)。

不过,大部分 Bean 实际都是无状态(没有定义可变的成员变量)的(比如 Dao、Service),这种情况下, Bean 是线程安全的。

对于有状态单例 Bean 的线程安全问题,常见的有两种解决办法:

  1. 在 Bean 中尽量避免定义可变的成员变量。
  2. 在类中定义一个 ThreadLocal 成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。

3.Spring Bean的作用域是什么?

Spring 中 Bean 的作用域通常有下面几种:

  • singleton : IoC 容器中只有唯一的 bean 实例。Spring 中的 bean 默认都是单例的,是对单例设计模式的应用。
  • prototype : 每次获取都会创建一个新的 bean 实例。也就是说,连续 getBean() 两次,得到的是不同的 Bean 实例。
  • request (仅 Web 应用可用): 每一次 HTTP 请求都会产生一个新的 bean(请求 bean),该 bean 仅在当前 HTTP request 内有效。
  • session (仅 Web 应用可用) : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean(会话 bean),该 bean 仅在当前 HTTP session 内有效。
  • application/global-session (仅 Web 应用可用):每个 Web 应用在启动时创建一个 Bean(应用 Bean),该 bean 仅在当前应用启动时间内有效。
  • websocket (仅 Web 应用可用):每一次 WebSocket 会话产生一个新的 bean。

4.使用Spring容器多次创建实例

默认情况下,当一个bean被定义在Spring容器中时,Spring会为这个bean创建一个单例实例。这意味着在整个Spring容器中,无论我们在哪里引用这个bean,都是引用的同一个实例。

然而,我们也可以配置Spring容器,使其为每个bean的请求创建一个新的实例,即多例模式。要实现这个目标,我们需要在bean的定义中使用scope属性,并将其值设置为prototype

下面是一个如何在Spring中实现多例bean的例子:

public class MyBean {  private String name;  public MyBean(String name) {  this.name = name;  }  public String getName() {  return name;  }  @Override  public String toString() {  return "MyPrototypeBean{" +  "name='" + name + '\'' +  '}';  }  
}

1.在配置类中使用注解,将scope属性设置为prototype

@Configuration  
public class AppConfig {  @Bean  @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)  public MyBean myBean(String name) {  return new MyBean(name);  }  
}

2.在需要时从Spring容器中请求这个bean。因为这是原型bean,所以每次请求都会得到一个新的实例。

 public class MainApp {  public static void main(String[] args) {  // 进行Bean管理ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);  MyBean bean1 = context.getBean("myBean", MyBean.class);  bean1.setName("Bean 1");  System.out.println(bean1);  MyBean bean2 = context.getBean("myBean", MyBean.class);  bean2.setName("Bean 2");  System.out.println(bean2);  // 因为它们是原型bean,所以它们不是同一个实例  System.out.println(bean1 == bean2); // 输出:false  System.out.println(bean1.getName() + " " + bean2.getName()); // 输出:Bean 1 Bean 2  }  
}

由于原型bean的生命周期是由Spring容器管理的,因此Spring容器会在每次请求时创建一个新的bean实例,并在不再需要时销毁它。

这意味着,如果你在你的代码中持有一个对原型bean的引用,并且这个引用不再被使用,那么这个bean实例可能会被垃圾收集器回收。因此,你应该始终从Spring容器中请求你需要的原型bean,而不是持有对它们的长期引用。

5.@Autowired和@Resource的区别是什么?

Autowired

Autowired 属于 Spring 内置的注解,默认的注入方式为byType(根据类型进行匹配),也就是说会优先根据接口类型去匹配并注入 Bean (接口的实现类)。

这会有什么问题呢? 当一个接口存在多个实现类的话,byType这种方式就无法正确注入对象了,因为这个时候 Spring 会同时找到多个满足条件的选择,默认情况下它自己不知道选择哪一个。

这种情况下,注入方式会变为 byName(根据名称进行匹配),这个名称通常就是类名(首字母小写)。就比如说下面代码中的 smsService 就是我这里所说的名称,这样应该比较好理解了吧。

// smsService 就是我们上面所说的名称
@Autowired
private SmsService smsService;

举个例子,SmsService 接口有两个实现类: SmsServiceImpl1SmsServiceImpl2,且它们都已经被 Spring 容器所管理。

// 报错,byName 和 byType 都无法匹配到 bean
@Autowired
private SmsService smsService;
// 正确注入 SmsServiceImpl1 对象对应的 bean
@Autowired
private SmsService smsServiceImpl1;
// 正确注入  SmsServiceImpl1 对象对应的 bean
// smsServiceImpl1 就是我们上面所说的名称
@Autowired
@Qualifier(value = "smsServiceImpl1")
private SmsService smsService;

Resource

@Resource属于 JDK 提供的注解,默认注入方式为 byName。如果无法通过名称匹配到对应的 Bean 的话,注入方式会变为byType

@Resource 有两个比较重要且日常开发常用的属性:name(名称)、type(类型)。

如果仅指定 name 属性则注入方式为byName,如果仅指定type属性则注入方式为byType,如果同时指定nametype属性(不建议这么做)则注入方式为byType+byName

// 报错,byName 和 byType 都无法匹配到 bean
@Resource
private SmsService smsService;
// 正确注入 SmsServiceImpl1 对象对应的 bean
@Resource
private SmsService smsServiceImpl1;
// 正确注入 SmsServiceImpl1 对象对应的 bean(比较推荐这种方式)
@Resource(name = "smsServiceImpl1")
private SmsService smsService;

简单总结一下:

  • @Autowired 是 Spring 提供的注解,@Resource 是 JDK 提供的注解。
  • Autowired 默认的注入方式为byType(根据类型进行匹配),@Resource默认注入方式为 byName(根据名称进行匹配)。
  • 当一个接口存在多个实现类的情况下,@Autowired@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired 可以通过 @Qualifier 注解来显式指定名称,@Resource可以通过 name 属性来显式指定名称。
  • @Autowired 支持在构造函数、方法、字段和参数上使用。@Resource 主要用于字段和方法上的注入,不支持在构造函数或参数上使用。

6.为什么更推荐构造函数注入

注入实现

final关键字:修饰的字段必须指定初值,要么直接赋值,要么指定构造函数。

这里指定final关键字后,可以通过@RequiredArgsConstructor构造器指定final关键字进行赋值(防止构造非final修饰的字段)。

对比字段注入

依赖关系:

  • 构造函数注入:依赖关系在类的构造函数中显式声明。强制要求在类的实例化时提供所有必需的依赖,使得依赖关系明确。

  • 字段注入:依赖关系通过注解隐式注入。依赖关系在类的内部声明,可能在代码阅读时不容易一目了然。

更容易测试:

  • 构造函数注入:在单元测试中,可以直接通过构造函数注入模拟对象。不依赖容器来注入依赖,可以更容易地进行单元测试。

  • 字段注入:需要利用反射实现模拟对象的注入。测试时需要额外配置来注入依赖,增加了复杂性。

性能问题:

  • 构造函数注入:基于构造函数,性能更好。

  • 字段注入:需要利用反射注入,性能较差。

  • 构造函数注入:在单元测试中,可以直接通过构造函数注入模拟对象。不依赖容器来注入依赖,可以更容易地进行单元测试。

  • 字段注入:需要利用反射实现模拟对象的注入。测试时需要额外配置来注入依赖,增加了复杂性。

性能问题:

  • 构造函数注入:基于构造函数,性能更好。

  • 字段注入:需要利用反射注入,性能较差。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于STM32的智能家居安防系统教程

目录 引言环境准备智能家居安防系统基础代码实现:实现智能家居安防系统 门窗传感器模块视频监控模块报警与通知模块用户界面与远程控制应用场景:家庭安防与监控常见问题与解决方案收尾与总结 引言 随着智能家居的普及,家庭安防系统成为保护…

艾瑞白皮书解读(一)丨为什么说数据工程是中国企业数据治理的最佳实践?

2024年7月 艾瑞咨询公司对国内数据治理行业进行了研究,访问了国内多位大中型企业数据治理相关负责人,深度剖析中国企业在数字化转型过程中面临到的核心数据问题后,重磅发布《2024中国企业数据治理白皮书》(以下简称“白皮书”&…

算法通关:017_1:二叉树及三种顺序的递归遍历

文章目录 题目思路代码运行结果 题目 二叉树及三种顺序的递归遍历 思路 代码 /*** Author: ggdpzhk* CreateTime: 2024-08-04** 二叉树及三种顺序的递归遍历* LeetCode 144. 二叉树的前序遍历* LeetCode 94. 二叉树的中序遍历* LeetCode 145. 二叉树的后序遍历* LeetCode 10…

龙迅LT8713SX 高性能TYPE-C/DP转三端口DP1.4/HDMI 2.0转换器,带音频

龙迅LT8713SX描述: LT8713SX是一个高性能类型-C/DP1.4到Type-C/DP1.4/HDMI2.0转换器,具有三个可配置的DP1.4/HDMI2.0/DP输出接口和音频输出接口。LT8713SX同时支持显示端口™单流传输(SST)模式和多流传输(MST&#xf…

Adobe Acrobat不支持图片格式转换PDF文件

我在将图片格式(PNG,JPEG)转换为PDF的过程中遇到了如下问题: 单文件的解决办法——在软件外实现转换: 使用照片打开图片 选择打印 打印机选择Adobe PDF,执行打印 选择PDF文件的保存位置,过一会儿可以正…

基本K8s搭建Jekins+gitee项目自动部署

这里写目录标题 1.基本K8s部署安装Jekins2.设置Jenkins国内镜像源2.安装Gitee插件1.安装Gitee Plugin2.验证安装Gitee Plugin 3.新建任务1.输入任务名称2.输入你gitee上的项目链接3.测试构建 4.查看项目在k8s集群master节点的位置1.确认 Jenkins Pod 名称2.使用kubectl exec到 …

视频如何生成二维码(自动生成二维码)完整教程

在企业中,产品视频二维码怎么制作,产品二维码怎么实现微信扫码便捷观看?上图文教程:视频二维码生成器/上传视频自动生成二维码完整教程。 目前市面上有很多工具,可以实现,比如草料二维码、酷播云二维码等等…

【Web开发手礼】探索Web开发的秘密(十四)-Vue2(1)Node.js的安装、Vue入门

主要介绍了Node.js的安装教程、Vue2常用的一些指令、声明周期!!! 文章目录 前言 Node.js安装 选择安装目录 验证NodeJS环境变量 配置npm的全局安装路径 切换npm的淘宝镜像 安装Vue-cli ​编辑 Vue2入门 引入vue.js文件 入门代码 常用指令 生…

前端(vue3)和后端(django)的交互

vue3中&#xff1a; <template><div><h2>注册页面</h2><form submit.prevent"submitForm"><label for"username">用户名&#xff1a;</label><input type"text" id"username" v-model…

AWS S3怎么收费的?一文带你搞懂!

Amazon Simple Storage Service&#xff08;S3&#xff09;是亚马逊网络服务&#xff08;AWS&#xff09;提供的一个高度可扩展的对象存储服务&#xff0c;广泛应用于数据存储、备份、归档和大数据分析等领域。S3的计费模式相对灵活&#xff0c;旨在满足不同用户的需求。本文中…

小试牛刀-walletconnect二维码及交互

目录 1.编写目的 2.实现功能 3.功能详解 依赖组件 3.1 二维码生成 3.1.1 初始化SignClient 3.1.2 创建会话空间获取WC协议uri 3.1.3 生成二维码供用户扫描 3.1.4 等待扫描 3.2 发送交易事务 3.2.1 创建交易事务 3.2.2 向用户发送交易事务 3.3 签名事务 3.3.1 接收…

安装VMware16

安装VMware16的步骤主要包括下载、‌安装和激活。‌ 下载VMware16 首先&#xff0c;‌需要从VMware官网下载VMware Workstation Pro 16的安装包。‌下载链接为https://customerconnect.vmware.com/cn/downloads/info/slug/desktop_end_user_computing/vmware_workstation_pro…

关于LLC知识2

LLC拓扑如下图所示&#xff0c;虚线框住的是LLC的核心部分&#xff0c;前面的部分是把输入交流电压经过整流和滤波使得在进入LLC的时候是直流电压&#xff08;带有纹波&#xff09;&#xff0c;如果忽略纹波&#xff0c;那么给LLC供电的就是稳定的直流电压。 LLC的稳态分析即&a…

浅谈线程组插件之jp@gc - Stepping Thread Group

浅谈线程组插件之jpgc - Stepping Thread Group jpgc - Stepping Thread Group 是一个高级线程组插件&#xff0c;专为Apache JMeter设计。相较于JMeter自带的基本线程组&#xff0c;此插件提供了更灵活、更精细的用户模拟方式&#xff0c;特别适合于模拟真实用户逐步增加的场…

MySQL--数据库备份

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 一、为什么要备份 备份&#xff1a;能够防止由于机械故障以及人为误操作带来的数据丢失&#xff0c;例如将数据库文件保存在了其它地方。 冗余&#…

密码学基础:搞懂Hash函数SHA1、SHA-2、SHA3(2)

目录 1.引入 2. SHA512-224\256 3.SHA-3 4.MD5 5.SM3 1.引入 上篇密码学基础&#xff1a;搞懂Hash函数SHA1、SHA-2、SHA3(1)-CSDN博客&#xff0c;我们先就将基础的SHA1\2讲解了&#xff0c;接下来我们继续聊SHA-3、SHA2变体SHA512_224\256等 2. SHA512-224\256 SHA512…

TPS和QPS达到多少才算高并发?

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storm…

pytorch学习笔记3 tensor索引和切片

dim 0 占先 切片 &#xff08;前N或者后N个&#xff09; &#xff1a;2 表示 0到2&#xff08;不包含2&#xff09;&#xff0c; 1&#xff1a;表示 1到末尾&#xff0c; -1表示最后一个元素&#xff0c;-2表示倒数第二个 0:28:2 表示从0到27隔点采样 &#xff1a;&#xff…

AC+AP组网

配置DHCP Switch1 <Huawei>sys [Huawei]undo in en [Huawei]vlan batch 10 20 30 40[Huawei]int vlan 10 [Huawei-Vlanif10]ip add 192.168.10.1 24 [Huawei-Vlanif10]quit[Huawei]int vlan 20 [Huawei-Vlanif20]ip add 192.168.20.1 24 [Huawei-Vlanif20]quit[Huawei]…

华水2022年专升本计算机培养方案

华水2022年专升本计算机培养方案 文章目录 华水2022年专升本计算机培养方案计科第一学期第二学期第三学期第四学期 软工第一学期第二学期第三学期第四学期 计科 第一学期 通识必修课 大学外语线性代数离散数学 专业基础课 高级语言程序设计 专业选修课 Java 第二学期 通识…