当前位置: 首页 > news >正文

Java知识点整理 16 — Spring Bean

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

一. 什么是 Spring Bean 

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

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

二. 通过例子来理解

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

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。

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(对象)

@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。

@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 注解的使用:

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

五. @Autowired 和 @Resource 的区别

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

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

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

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

// 报错,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(类型)。

// 报错,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。

如何配置:

// 注解方式
@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 销毁之前执行的方法。

相关文章:

Java知识点整理 16 — Spring Bean

在之前的文章 Java知识点整理 8 — Spring 简介 中介绍了 Spring 的两大核心概念 IoC 和 AOP,但对 Spring Bean 的介绍不全面,本文将补充 Spring 中 Bean 的概念。 一. 什么是 Spring Bean 在 Spring 官方文档中,对 bean 的定义为&#xf…...

Nvidia Jetson/RK3588+AI双目立体相机,适合各种割草机器人、扫地机器人、AGV等应用

双目立体视觉是基于视差原理,依据成像设备从不同位置获取的被测物体的图像,匹配对应点的位置偏移,得到视差数据,进而计算物体的空间三维信息。为您带来高图像质量的双目立体相机,具有高分辨率、低功耗、远距离等优点&a…...

springboot使用feign调用不依赖cloud

在使用spring boot调用第三方api中,常用的是okhttp、apache http client等,但是直接使用下来还是有点繁琐,需要手动转换实体。 在springcloud中有个openfeign调用,第一次体验到调用接口还能这么丝滑。注解写道接口上,…...

springboot中使用springboot cache

前言&#xff1a;SpringBoot中使用Cache缓存可以提高对缓存的开发效率 此图片是SpringBootCache常用注解 Springboot Cache中常用注解 第一步&#xff1a;引入依赖 <!--缓存--><dependency><groupId>org.springframework.boot</groupId><artifactId…...

Promise,async/await的运用

一&#xff0c;了解Promise Promise是异步编程的一种解决方案&#xff0c;它是一个对象&#xff0c;可以获取异步操作的消息&#xff0c;它的出现避免了地狱回调。 &#xff08;1&#xff09;Promise的实例有三个状态&#xff1a; Pending&#xff08;进行中&#xff09; Re…...

图论·多源最短路径Floyddijsktra

例题地址 多源最短路径 多个源点多个终点可以使用Floyd算法直接求各源点到终点的最短距离&#xff0c;也可以直接多次使用dijsktra算法求单源点到终点的最短距离 Floyd算法 使用条件 多源最短路径权值正负皆可 核心思想&#xff1a;动态规划 子问题&#xff1a; 设(A,B)…...

微服务 | Springboot整合GateWay+Nacos实现动态路由

1、简介 路由转发 执行过滤器链。 ​ 网关&#xff0c;旨在为微服务架构提供一种简单有效的统一的API路由管理方式。同时&#xff0c;基于Filter链的方式提供了网关的基本功能&#xff0c;比如&#xff1a;鉴权、流量控制、熔断、路径重写、黑白名单、日志监控等。 基本功能…...

做google SEO 有哪些好用的工具?这12款谷歌SEO工具值得收藏!

1、Google Trends 谷歌旗下一款基于搜索数据推出的一款免费分析工具 外贸人有句老话&#xff0c;七分靠选品&#xff0c;三分靠运营。在你开始做独立站之前&#xff0c;在你不清楚你的行业在Google上面能否有足够的流量时&#xff0c;那么Google Trends则是你最好的工具。 你只…...

【变频调速在锅炉引风机控制中的应用】

变频调速在锅炉引风机控制中的应用 变频器的选型 变频器是利用电力半导体器件的通断作用将工频电源变换为另一种频率的电能控制装置,能宏观对交流异步电机软启动,变频调速,提高运转精度,改变功率因数,过流/过压/过载保护等功能,国内技术较领先的品牌有汇川、欧瑞(原烟台…...

网络配置(IP、NETMASK、GATEWAY、DNS、DHCP) <持续更新中>

参考&#xff1a; 初学Linux之网络配置(IP、NETMASK、GATEWAY、DNS、DHCP)-CSDN博客【学习笔记】网关 & 路由_网关和路由-CSDN博客【学习笔记】计算机网络 IP地址与MAC地址_根据mac分配ip-CSDN博客【学习笔记】TCP 和 UDP 协议_tcp 发送 syn 应答没有syn ack-CSDN博客 一…...

【ArcGIS 脚本工具】拯救密恐,隐藏唯一值渲染图层的标记符号

最近拿到了【Hello 图狗】制作的三调/变更样式符号库&#xff0c;确实比之前网上下载的版本好用很多。 ArcGIS Pro三调23变更符号库V1.02&#xff08;汇总&#xff09;_中大比例尺.stylx和样式属性对调 不过使用过程中触发了一个旧病&#xff0c;就是匹配样式之后&#xff0c;…...

tensorflow学习1.3-创建会话,启动会话

tensorflow学习1.3-创建会话&#xff0c;启动会话 会话的由来与作用由来作用 会话的定义与结构定义 用法基本用法上下文管理器执行部分计算图获取多个结果 总结 练习代码报错原因&#xff1a;TensorFlow 2.x中的Eager Execution使用兼容模式来启用SessionEager Execution和计算…...

QT基本对话框(基本对话框、工具盒类、进度条、调色板与电子钟、可扩展对话框、程序启动画面)

此篇文章通过实例介绍基本对话框的用法。首先介绍标准文件对话框&#xff08;QFileDialog&#xff09;、标准颜色对话框&#xff08;QColorDialog&#xff09;、标准字体对话框&#xff08;QFontDialog&#xff09;、标准输入对话框&#xff08;QInputDialog&#xff09;以及标…...

Docker 部署 MariaDB 数据库 与 Adminer 数据库管理工具

文章目录 MariaDBmariadb.cnf开启 binlog Adminerdocker-compose.ymlAdminer 连接 MariaDB MariaDB MariaDB是一个流行的开源关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它是MySQL的一个分支和替代品。 官网&#xff1a;https://mariadb.com/镜像&#xff…...

qt 可以在一个函数中读一个文件,然后再将内容写入另一个文件中

是的&#xff0c;Qt 允许你在一个函数中读取一个文件的内容&#xff0c;并将这些内容写入到另一个文件中。这可以通过结合使用 QFile 和 QTextStream&#xff08;或 QDataStream&#xff0c;取决于你的具体需求&#xff09;来实现。以下是一个简单的示例&#xff0c;展示了如何…...

Dijkstra算法C代码

一个带权图n个点m条边&#xff0c;求起点到终点的最短距离 先定义一个邻接矩阵graph&#xff0c;graph[i][j]表示从i到j的距离&#xff0c;i到j没有路就表示为无穷 然后定义一个visit数组&#xff0c;visit[i]表示i结点是否被访问 然后定义一个dist数组&#xff0c;dist[i]表…...

P1064 [NOIP2006 提高组] 金明的预算方案

[NOIP2006 提高组] 金明的预算方案 题目描述 金明今天很开心&#xff0c;家里购置的新房就要领钥匙了&#xff0c;新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是&#xff0c;妈妈昨天对他说&#xff1a;“你的房间需要购买哪些物品&#xff0c;怎么布置&#xff0…...

大型企业组网如何规划网络

大型企业组网是一个复杂的过程&#xff0c;它需要细致的规划和设计&#xff0c;以确保网络能够满足企业的业务需求&#xff0c;同时保证性能、安全性和可扩展性。以下是规划大型企业网络的一些关键步骤和考虑因素&#xff1a; 1. 需求分析 业务需求&#xff1a;与各个业务部门…...

java:aocache的单实例缓存(二)

之前一篇博客《java:aocache的单实例缓存》介绍了aoocache使用注解AoCacheable实现单实例缓存的方式&#xff0c;同时也指出了这种方式的使用限制&#xff0c;就是这个注解定义的构造方法&#xff0c;不能再创建出新实例。 为了更灵活方便的实现单实例。aocache最新版本0.4.0增…...

ElasticSearch安装部署

简介 Elasticsearch 是一个开源的分布式搜索和分析引擎&#xff0c;用于实时地存储、检索和分析大数据量。它基于 Apache Lucene 搜索引擎库构建而成&#xff0c;提供了一个强大、稳定且易于扩展的搜索解决方案。 主要特点和用途&#xff1a; 分布式存储和搜索&#xff1a; E…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言&#xff1a; 在Java编程中&#xff0c;类的生命周期是指类从被加载到内存中开始&#xff0c;到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期&#xff0c;让读者对此有深刻印象。 目录 ​…...

DingDing机器人群消息推送

文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人&#xff0c;点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置&#xff0c;详见说明文档 成功后&#xff0c;记录Webhook 2 API文档说明 点击设置说明 查看自…...