Java知识点整理 16 — Spring Bean

devtools/2024/9/20 3:51:38/ 标签: java, spring, bean

在之前的文章 Java知识点整理 8 — Spring 简介 中介绍了 Spring 的两大核心概念 IoC 和 AOP,但对 Spring Bean 的介绍不全面,本文将补充 Spring 中 Bean 的概念。

一. 什么是 Spring Bean 

在 Spring 官方文档中,对 bean 的定义为:构成应用程序主干并由 Spring IoC 容器管理的对象称为 beanbean 是由 Spring IoC 容器实例化、组装和管理的对象。

开发者需要告诉 IoC 容器协助管理哪些对象,这个是通过配置元数据来定义的。配置元数据可以是 XML文件(较老)、注解或者 Java 配置类。

二. 通过例子来理解

首先有一个 Student 类,里面有两个成员变量 id 和 name,并提供 set、get方法。

java">public class Student {private Integer id;private String 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;}
}

另一个类是 StudentManager,有一个 Student 的对象,提供了 setStudent 方法初始化 Student 对象,并且它的 show 方法能够打印这个 student 的 id 和 name。

java">public class StudentManager {private Student student;public void setStudent(Student student) {this.student = student;}public void show() {System.out.println(student.getId());System.out.println(student.getName());}
}

分析以上两段代码发现,两个类之间高度耦合,后者依赖于前者。假如没有及时对 StudentManager 的 student 绑定对象,却调用了 show 方法,那么程序就会报空指针异常的错误。因此 Spring 提供了 IoC(控制反转)和 DI(依赖注入)进行解耦。

在 Spring 中不需要自己创建对象,只需要告诉 Spring,哪些类需要创建,然后在启动项目时 Spring 就会自动帮助创建对应的对象,并且只存在一个类的实例。这个类的实例也就是 Bean,而这种模式通常称为单例模式,即一个类只有一个实例。

继续思考,开发者该如何告诉 Spring 哪些类需要创建对象呢?

最简单最常用的方式就是 Java 注解配置。也就是将一个类声明为 Bean 所需要的注解。

声明含义
@Component通用注解,可标注任意类为 Spring 组件。如果一个 Bean 不知道属于哪个层,可以使用该注解标注
@Repository当前类在持久层(Dao层),主要用于数据库相关操作。
@Service当前类在业务逻辑层,主要涉及复杂的逻辑。
@Controller当前类在控制层,主要用于接受用户请求并调用 Service 层返回数据给前端页面。

其实以上四种声明方式效果完全一致,使用不同的关键词是让开发者快速了解该类属于哪一层。

例如,在刚才的 Student 类前加上 @Component 注解,就告诉 Spring:你要在项目创建运行时帮我创建 Student 类的 Bean(对象)

java">@Component
public class Student {private Integer id;private String 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;}
}

此时"依赖"添加完毕,但还没结束。虽然让 Spring 帮助我们创建了对象,但 StudentManager 怎么知道这个被创建的对象在哪呢?所以接下来要告诉 StudentManager 刚才 Spring 帮助创建的 Bean(对象)在哪,也就是注入 Bean

注入注解
声明含义
@Autowired根据 Bean 的 Class 类型自动装配
@Inject字面意思注入
@Resource字面意思资源,根据 Bean 的属性名称(id / name)自动装配

例如,在 StudentManager 类中声明成员变量 Student 的前面加上 @Autowired,Spring 会自动注入一个 Bean。

java">@Component
public class StudentManager {@Autowiredprivate Student student;public void show() {System.out.println(student.getId());System.out.println(student.getName());}
}

三. @Bean 注解的使用

  • @Bean 注解作用在方法上,产生一个 Bean 对象,然后将其交给 Spring 管理。Spring 会将这个 Bean 对象放在自己的 IoC 容器中。
  • @Bean 方法名与返回类名一致,首字母小写。
  • @Component、@Repository、@Controller、@Service 这些注解只局限于自己编写的类,@Bean 注解能把第三方库中的类实例加入 IoC 容器并交给 Spring 管理。
  • @Bean 一般和 @Component 或 @Configuration 一起使用。

四. @Component 和 @Bean 的区别

  • @Component 注解作用于类,@Bean 作用于方法。
  • @Component 通常是通过类路径扫描来自动侦测以及自动装配到 Spring 容器中,可以使用 @ComponentScan 注解定义要扫描的路径,从中找出标识了需要装配的类,并自动装配到 Spring 的 bean 容器中。@Bean 注解通常是在标有该注解的方法中定义产生这个 bean,它告诉了 Spring 这是某个类的实例,在需要时给我。
  • @Bean 注解比 @Component 注解的自定义性更强,而且很多地方只能通过@Bean 注解来注册 bean,比如第三方库。

@Bean 注解的使用:

java">@Configuration //标记该类为配置类,提供配置信息给 Spring 容器。
public class AppConfig {@Beanpublic TransferService transferService() {return new TransferServiceImpl();}
}

五. @Autowired 和 @Resource 的区别

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

但如果一个接口存在多个实现类,byType 这种方式可能无法正确注入对象,因为 Spring 找到了多个满足条件的选择,默认情况下不知道选哪一个。这种情况下,注入方式会变为 byName,即根据名称匹配,这个名称通常是类名,如下面的 SmsService。

java">// smsService 就是上面所说的名称
@Autowired
private SmsService smsService;

如果 SmsService 接口有两个实现类:SmsServiceImpl1 和 SmsServiceImpl2,且它们都被 Spring 容器管理。

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

通过 @Qualifier 注解能够显式指定名称,而不是依赖变量名称。

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

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

java">// 报错,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。
  • 当一个接口存在多个实现类时,两个注解都需要通过名称才能正确匹配到对应的 Bean。@Autowired 可以通过 @Qualifier 注解来显示指定名称,@Resource 可以通过 name 属性来显式指定名称。
  • @Autowired 支持在构造函数、方法、字段和参数上使用。@Resource 主要用于字段和方法上的注入,不支持在构造函数或参数上使用。

六. 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(仅 Web 应用)每个 Web 应用在启动时创建一个 bean(应用 bean),该 bean 仅在当前应用启动时间内有效。
websocket(仅 Web 应用)每次 WebSocket 会话产生一个新的 bean

如何配置:

java">// 注解方式
@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Person personPrototype() {return new Person();
}

七. Bean 的生命周期

1. 创建 Bean 的实例:Bean 容器首先会找到配置文件中的 Bean 定义,然后使用 Java 反射 API 来创建 Bean 的实例。

2. Bean 属性赋值/填充:为 Bean 设置相关属性和依赖,例如 @Autowired 等注解注入对象、@Value 注入值、@Resource 注入各种资源等。

3. Bean 初始化:

  • 如果 Bean 实现了 BeanNameAware 接口,调用 setBeanName() 方法,传入 Bean 的名字。
  • 如果 Bean 实现了 BeanClassLoaderAware 接口,调用 setBeanClassLoader() 方法,传入 ClassLoader 对象的实例。
  • 与上面的类似,如果实现了其他 *.Aware 接口,就调用相应的方法。
  • 如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessBeforeInitialization() 方法
  • 如果 Bean 实现了 InitializingBean 接口,执afterPropertiesSet() 方法。
  • 如果 Bean 在配置文件中的定义包含 init-method 属性,执行指定的方法。
  • 如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessAfterInitialization() 方法。

4. 销毁 Bean:销毁并不是说立刻把 Bean 销毁掉,而是把 Bean 的销毁方法先记录下来,将来需要销毁 Bean 或者销毁容器的时候,就调用这些方法去释放 Bean 所持有的资源。

  • 如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。
  • 如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的 Bean 销毁方法。或者,也可以直接通过 @PreDestroy 注解标记 Bean 销毁之前执行的方法。

http://www.ppmy.cn/devtools/56237.html

相关文章

基于大语言模型LangChain框架:知识库问答系统实践

ChatGPT 所取得的巨大成功,使得越来越多的开发者希望利用 OpenAI 提供的 API 或私有化模型开发基于大语言模型的应用程序。然而,即使大语言模型的调用相对简单,仍需要完成大量的定制开发工作,包括 API 集成、交互逻辑、数据存储等…

Altair SimSolid无网格快速结构仿真软件

Altair SimSolid软件作为一款快速无网格划分工具,凭借其独特的算法和计算能力,简化了工程师和分析师在进行复杂结构分析时的操作。它不仅提高了分析效率,降低了出错的可能性,还为用户提供了丰富的分析功能和直观易用的操作体验。在…

自然语言处理-BERT处理框架-transformer

目录 1.介绍 2.Transformer 2.1 引言 2.2 传统RNN网络的问题 2.3 整体架构 2.4 Attention 2.5 Self-Attention如何计算 3.multi-headed机制 4. BERT训练方法 1.介绍 BERT:当前主流的解决框架,一站式搞定NLP任务。(解决一个NLP任务时的考虑…

【代码随想录数据结构刷题记录】

文章目录 一、代码随想录数据结构刷题记录 一、代码随想录数据结构刷题记录 2024-04-08-代码随想录算法训练营第六天[LeetCode242有效的字母异位词、LeetCode349两个数组的交集 、LeetCode202快乐数 、LeetCode1. 两数之和] 2024-04-09-代码随想录算法训练营第七天[LeetCode4…

Tomcat调优

文章目录 一、JVM组成JVM组成堆和栈的拓展垃圾回收垃圾确定方法垃圾回收基本算法 分代堆内存垃圾回收策略堆内存分代 二、参数调整java 内存调整相关参数Tomcat的JVM的参数设置 在目前流行的互联网架构中,Tomcat在目前的网络编程中是举足轻重的,由于Tomc…

CSS 核心知识点 - grid

思维导图 参考网址: https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_grid_layout 一、什么是 grid? CSS Grid布局是在CSS3规范中引入的一种新的布局方式,旨在解决传统布局方法(如浮动、定位、表格布局)存在的许多问题。C…

CAN和CANFD数据写入.asc文件的dll

因为工作需要,需要做一些硬件不是CANoe的上位机(比如说周立功CAN,NI-CAN),上位机需要有记录数据的功能,所以用Qt制作了一个记录数据的dll,方便重复使用(因为有的客户指定了编程软件,…

SmartEDA革新来袭:融合Multisim与Proteus精髓,引领电子设计新纪元!

在电子设计领域,每一次技术的革新都如同春风化雨,滋润着设计师们的心田。今天,我们迎来了一个划时代的电子设计自动化(EDA)工具——SmartEDA,它不仅融合了业界知名的Multisim和Proteus的精华,更…

在 Java 中的使用Selenium 测试框架

Selenium 测试框架:在 Java 中的使用 Selenium 测试框架就是这样一个强大的工具,它为 Web 应用的自动化测试提供了全面且高效的解决方案。 一、Selenium 简介 Selenium 是一个开源的自动化测试工具集,专门用于测试 Web 应用程序。它支持多…

nuxt实现vuex持久化

前言: 此处不借助插件实现 store 本地持久化 所有状态持久化 使用 vuex 里面的 replaceState 方法还原 store 的根状态 API 参考 | Vuex 创建 store-cache.js 文件 在 plugins 目录下创建 store-cache.js 文件; store-cache.js export default (ctx) &g…

shell编程实战

1.1 shell脚本编程的步骤 需求分析:确定功能 命令测试:确定脚本需要的关键命令 编辑脚本 测试脚本 1.2 操作 1.2.1 实验一 1.需求描述 (1)统计网络中的服务器的mac 注:ARP,地址解析协议 注: (2)检查哪些主机开…

Ubuntu开机后图像化界面消失只有命令行界面

ubuntu重新安装cpp库时突然黑屏,打开之后,只能手动输入用户名和密码才能登陆,当时最坏的结果就是重新安装系统,但是还是得抢救一下,万幸的是抢救成功了!!! 于是来到第一个博客 参考…

收银系统源码-千呼新零售【分销商城】

千呼新零售2.0系统是零售行业连锁店一体化收银系统,包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体,线上线下数据全部打通。 适用于商超、便利店、水果、生鲜、母婴、服装、零食、百货、宠物等连锁店使用。 详细介绍请…

【cf】Edu Codeforces Round 167(Div.2)题解 A - E

文章目录 A. Catch the CoinB. Substring and Subsequence(贪心)C. Two Movies(贪心)D. Smithing Skill(贪心双指针)E. Distance to Different(dp) A. Catch the Coin y 小于 -1 就…

Talking Web

1. curl 1.1 http curl http://127.0.0.1:80 向目标主机端口发送http请求 1.2 httphead curl -H “Host: 18ed3df584cd48328b5839443aa7b42b” http://127.0.0.1:80 1.3 httppath curl http://127.0.0.1:80/853c64cd218f80d0a59665666fb2ab80 1.4 URL编码路径 &#xff0…

光学相机市场格局:中国光学相机市场评估及未来发展趋势研究报告

欢迎关注GZH《光场视觉》 光学相机行业定义 光学相机是一种利用光学镜头和感光材料(如胶片)或数字传感器来捕捉图像的装置。光学相机,也常被称作传统相机或胶片相机,其工作原理基于光的折射和聚焦。当光线通过相机的镜头进入时&…

从我邮毕业啦!!!

引言 时间过的好快,转眼间就要从北邮毕业了,距离上一次月度总结又过去了两个月,故作本次总结。 PS: https://github.com/WeiXiao-Hyy/blog整理了后端开发的知识网络,欢迎Star! 毕业🎓 6月1号完成了自己的…

# Kafka_深入探秘者(1):初识 kafka

Kafka_深入探秘者(1):初识 kafka 一、kafka 特性 1、Kafka :最初是由 Linkedln 公司采用 Scala 语言开发的一个多分区、多副本并且基于 ZooKeeper 协调的分布式消息系统,现在已经捐献给了 Apache 基金会。目前 Kafka…

【websocket】websocket网课视频记录

仅个人方便回顾。 【WebSocket入门与案例实战-哔哩哔哩】 https://b23.tv/2p1f9t2 课程对应代码仓库: https://gitee.com/duoli-java/websocket-demo.git

[图解]企业应用架构模式2024新译本讲解18-活动记录2

1 00:00:00,940 --> 00:00:04,890 接下来,就是要把这个列表输出到控制台 2 00:00:06,490 --> 00:00:12,280 这里面有3个 3 00:00:15,420 --> 00:00:17,480 Id有了,姓 4 00:00:18,600 --> 00:00:28,500 一个一个取,ID&#xff…