Bean 作用域和生命周期
✏️作者:银河罐头
📋系列专栏:JavaEE
🌲“种一棵树最好的时间是十年前,其次是现在”
目录
- lombok的使用
- 案例引入
- 作用域定义
- singleton单例作用域
- prototype原型作用域(多例作用域)
- request请求作用域
- session会话作用域
- application全局作用域
- websocket
- 设置作用域
- Spring 执行流程
- Bean 的生命周期
- 代码演示
lombok的使用
1.添加依赖
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.26</version><scope>provided</scope>
</dependency>
2.在实体类使用 lombok 注解。
package com.java.demo.entity;
import lombok.Getter;
import lombok.Setter;//lombok
@Setter
@Getter
public class User {private int id;private String name;
}


案例引入
package com.java.demo.entity;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
//lombok
@Setter
@Getter
@ToString
public class User {private int id;private String name;
}
package com.java.demo.component;
import com.java.demo.entity.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;@Component
public class UserBeans {@Beanpublic User user(){User user = new User();user.setId(1);user.setName("张三");return user;}
}
package com.java.demo.controller;
import com.java.demo.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class UserController {@Autowiredprivate User user;public void printUser(){System.out.println(user);User myUser = user;myUser.setName("悟空");System.out.println("myUser -> " + myUser);System.out.println("user -> " + user);}
}
package com.java.demo.controller;
import com.java.demo.entity.User;
import org.springframework.stereotype.Controller;
import javax.annotation.Resource;@Controller
public class UserController2 {@Resourceprivate User user;public void printUser2(){System.out.println("user -> " + user);}
}
package com.java.demo;
import com.java.demo.controller.UserController;
import com.java.demo.controller.UserController2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {ApplicationContext context =new ClassPathXmlApplicationContext("spring-config.xml");UserController userController =context.getBean("userController",UserController.class);userController.printUser();UserController2 userController2 =context.getBean("userController2",UserController2.class);userController2.printUser2();}
}
我的预期结果是:
User(id=1, name=张三)
myUser -> User(id=1, name=悟空)
user -> User(id=1, name=张三)
user -> User(id=1, name=张三)

但运行之后结果是这样。
为什么会出现这种现象?
原因是 Bean 的作用域(scope)默认是单例模式,此 Bean 在 整个 spring 容器中只有一份。
作用域定义
Bean 的 6 种作用域
singleton单例作用域
无状态的 Bean 使用该作用域。无状态指的是Bean 对象的属性状态不需要更新。
spring 默认使用该作用域。
prototype原型作用域(多例作用域)
每次对该作用域下的 Bean 请求都是创建新的实例。获取及注入 Bean 都是新的对象实例。
通常有状态的 Bean 使用该作用域。
request请求作用域
每次 http 请求都会创建新的 Bean 实例。一次 http 请求和响应共享bean.
适用于 springMVC/spring Web
session会话作用域
每次 session 会话共享一个 Bean.
适用于 springMVC/spring Web
application全局作用域
application. 一个 http servlet context 共享一个 Bean.
适用于 springMVC/spring Web
websocket
限定 Spring WebSocket 中使用
注意:在普通的 Spring 项⽬中只有前两种作用域。
设置作用域

回到之前的代码案例。
可以把 Bean 作用域 设置成 多例作用域。
要在存 Bean 之前就设置作用域。
package com.java.demo.component;
import com.java.demo.entity.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;@Component
public class UserBeans {@Bean@Scope("prototype")public User user(){User user = new User();user.setId(1);user.setName("张三");return user;}
}

//第2种设置方式:
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

给出的提示也验证了前面所说的 spring core 项目 Bean 只能设置 2 种 作用域 :singleton 和 prototype.
@Scope 可以修饰方法,也可以修饰 类。
Spring 执行流程
1.启动容器

加载配置文件。
2.根据配置完成 Bean 初始化。

扫描 base-package 目录底下所有类,找到 加了五大类注解的类
3.把 Bean 存到 spring 容器中。

4.装配 Bean 的属性。(取 Bean)
如果 Bean 对象的属性里包含其他 Bean 对象,可以通过 @Autowired 、@Resource 注入


Bean 的生命周期
1.实例化 Bean, 为 Bean 分配内存空间。
2.设置属性(Bean 装配和注入)
3.Bean初始化
- 各种通知:如 BeanNameAware、BeanFactoryAware、 ApplicationContextAware 的接口方法;
- 初始化前置方法。
- 初始化方法(设置了才会执行):1.注解方式:@PostConstruct 2. xml 方式:init-method 方法
- 初始化后置方法。
4.使用 Bean
5.销毁 Bean
代码演示
<?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:content="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 https://www.springframework.org/schema/context/spring-context.xsd"><content:component-scan base-package="com.java.demo"></content:component-scan><bean id="beanComponent"class="com.java.demo.component.BeanComponent" init-method="myInit"></bean>
</beans>
ApplicationContext 没有销毁方法。ClassPathXmlApplicationContext 有销毁方法。
package com.java.demo.component;
import org.springframework.beans.factory.BeanNameAware;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;public class BeanComponent implements BeanNameAware {@Overridepublic void setBeanName(String s) {System.out.println("执行了通知 BeanName -> " + s);}/*** XML 方式的初始化方法*/public void myInit(){System.out.println("XML 方式的初始化方法");}@PostConstructpublic void postConstruct(){System.out.println("注解 方式的初始化方法");}public void sayHi(){System.out.println("执行 sayHi() 方法");}@PreDestroypublic void doPreDestroy(){System.out.println("do PreDestroy");}
}
package com.java.demo;
import com.java.demo.component.BeanComponent;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {ClassPathXmlApplicationContext context= new ClassPathXmlApplicationContext("spring-config.xml");BeanComponent beanComponent =context.getBean("beanComponent",BeanComponent.class);beanComponent.sayHi();context.destroy();}
}

注解初始化方法 优先级高于 XML 初始化方法。
设置属性和初始化这两个步骤能颠倒吗?
不能,如果先初始化,在初始化代码中如果调用了依赖的属性的方法,就会报错(此时依赖的属性还没有注入)。
如果我想完善代码,想看到更详细的 Bean 的生命周期流程,能看到其他的通知,初始化前置方法,初始化后置方法。代码如下:
package com.java.demo.component;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;public class BeanComponent implements BeanNameAware , BeanFactoryAware , ApplicationContextAware {@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {System.out.println("执行了通知 ApplicationContext -> " + applicationContext);}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {System.out.println("执行了通知 BeanFactory -> " + beanFactory);}@Overridepublic void setBeanName(String s) {System.out.println("执行了通知 BeanName -> " + s);}/*** XML 方式的初始化方法*/public void myInit(){System.out.println("XML 方式的初始化方法");}@PostConstructpublic void postConstruct(){System.out.println("注解 方式的初始化方法");}public void sayHi(){System.out.println("执行 sayHi() 方法");}@PreDestroypublic void doPreDestroy(){System.out.println("do PreDestroy");}}
package com.java.demo;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("postProcessBeforeInitialization " + beanName + " 调用初始化前置方法");return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("postProcessAfterInitialization " + beanName + " 调用初始化后置方法");return bean;}
}
<?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:content="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 https://www.springframework.org/schema/context/spring-context.xsd"><content:component-scan base-package="com.java.demo"></content:component-scan><bean id="beanComponent"class="com.java.demo.component.BeanComponent" init-method="myInit" ></bean><bean id="myBeanPostProcessor"class="com.java.demo.MyBeanPostProcessor"></bean>
</beans>
package com.java.demo;
import com.java.demo.component.BeanComponent;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {ClassPathXmlApplicationContext context= new ClassPathXmlApplicationContext("spring-config.xml");BeanComponent beanComponent =context.getBean("beanComponent",BeanComponent.class);beanComponent.sayHi();context.destroy();//context.close();}
}

相关文章:
Bean 作用域和生命周期
✏️作者:银河罐头 📋系列专栏:JavaEE 🌲“种一棵树最好的时间是十年前,其次是现在” 目录 lombok的使用案例引入作用域定义singleton单例作用域prototype原型作用域(多例作用域)request请求作用域session会话作用域ap…...
PMP考试常见13个固定套路
一、变更批准之后 变更批准后要做三件事: 1、在变更日志中记录 2、通知相关干系人 3、更新项目管理计划 二、风险的情景题 1、先判断风险识别了,还是风险发生了。 2、若是风险识别,按风险管理程序走; 3、若是风险发生,则应采取应急措施…...
Leecode101 ——对称二叉树
对称二叉树:Leecode 101 leecode 101 对称二叉树 根据题目描述,首先想清楚,对称二叉树要比较的是哪两个节点。对于二叉树是否对称,要比较的是根节点的左子树与根节点的右子树是不是相互翻转的,其实也就是比较两个树,…...
JVM学习随笔03——Java堆中new一个对象的步骤
目录 一、进行类加载 二、堆中分配内存 1、怎么输出GC日志: 2、内存分配的两种方式: 3、内存分配过程中并发控制的两种方式: 三、内存空间初始化 四、对象头初始化(对象头包含哪些信息?) 五、执行构…...
虹科方案 | CEMEX 使用HK-Edgility 智能边缘计算平台简化其企业 WAN 管理和运营
一、应对价值 130 亿美元的跨国企业的网络挑战 “我们选择 Edgility 是因为其卓越的管理和协调功能,它为我们提供了一个端到端的工具集,可以经济高效地部署和管理我们边缘设备的生命周期。” —— Fernando Garcia -Villaraco Casero, CEMEX 全球IT 战略…...
rk3568 系统移植和编译
1。 硬件问题 尽量根据原版 evb 开发版 pcb 进行布线和移植,切记不可自行走线。 emmc 和 ddr4 选型都有要求的,按照硬件手册进行设计 2。软件问题 2.1 目前固件系统选用1.3.2 版本进行设计 解压后运行 .repo/repo/repo sync -c 更新代码 2.2 ubo…...
深度解析C++异常处理机制:分类、处理方式、常见错误及11新增功能
C 基础知识 八 异常处理 上篇 一、基础1. 异常的概念2. 异常的分类2.1 内置异常2.2 自定义异常 3. 异常的处理方式3.1 try-catch 语句3.2 throw 语句3.3 noexcept 修饰符3.4 finally 语句块 二、 异常处理机制1 try-catch 语句块2 异常处理流程3 标准异常类 三、 抛出异常1 thr…...
FPGA时序约束(四)主时钟、虚拟时钟和时钟特性的约束
系列文章目录 FPGA时序约束(一)基本概念入门及简单语法 FPGA时序约束(二)利用Quartus18对Altera进行时序约束 FPGA时序约束(三)时序约束基本路径的深入分析 文章目录 系列文章目录前言主时钟约束跨时钟域…...
JNI开发
文件结构(选中的为生成的) CMake构建不需要执行命令,会自动生成so文件打包进apk Android mk构建需要执行命令生成so文件,再打包进apk。命令如下。 # 在jni目录下执行 # 生成com_demo_cppproject_OtherNdkTest.h头文件 javac -h .…...
JAVA有哪些特点?
JAVA有以下特点: 综上所述,Java作为一种先进的面向对象编程语言,具有简单、可移植、健壮、高性能、多线程、动态性、跨平台、开放性和安全性等众多特点,已经成为广泛使用的编程语言之一。 简单易学:JAVA语言的语法与C语…...
使用读写锁提高并发
我们想要的是:允许多个线程同时读,但只要有一个线程在写,其他线程就必须等待。 ReadWriteLock ReadWriteLock的作用: 只允许一个线程写入(其他线程既不能写入也不能读取);没有写入时…...
使用@PropertySource加载配置文件
1.PropertySource和PropertySources注解 1.1.PropertySource注解概述 PropertySource注解是Spring 3.1开始引入的配置类注解。通过**PropertySource注解可以将properties配置文件中的key/value存储到Spring的Environment中,Environment接口提供了方法去读取配置文…...
事务及分布式事务解决方案
基础概念 1.1.事务 事务可以看做是一次大的活动,它由不同的小活动组成,这些活动要么全部成功,要么全部失败。 1.2.本地事务 在计算机系统中,更多的是通过关系型数据库来控制事务,利用数据库本身的事务特性来实现&a…...
【思科、华为、华三、锐捷网络设备巡检命令】
华三 screen-1ength disable 取消分页 displayversion 查看版本 displayclock 查看日期时钟 displayfan 查看风扇状态 displaypower 查看电源信息 displaycpu-usage 查看CPU利用率 displaymemory 查看内存利用率 display environment 查看温度信息 display device 查看设备信息…...
代码随想录算法训练营第五十二天
代码随想录算法训练营第五十二天| 300.最长递增子序列,674. 最长连续递增序列,718. 最长重复子数组 300.最长递增子序列674. 最长连续递增序列718. 最长重复子数组 300.最长递增子序列 题目链接:最长递增子序列 这里是不用处理if nums[i] &l…...
【Linux网络】传输层中UDP和TCP协议
文章目录 1、再谈端口号2、UDP协议3、TCP协议3.1 TCP协议段格式3.2 TCP的三次握手和四次挥手(连接管理机制)3.3 TCP的滑动窗口3.4 TCP的流量控制3.5 拥塞控制3.6 延迟应答和捎带应答3.7 面向字节流和粘包问题3.8 TCP总结 1、再谈端口号 端口号port标识一…...
工具︱ Web3加密浏览器Brave有什么特别之处?
使用浏览器来上网访问和获取各种信息和资源已经成为传统互联网民的普遍活动,下一代互联网协议Web3的核心特点是去中心化,即不依赖于中心化的服务器和数据中心,而是通过分布式的网络节点来实现数据存储和传输。 浏览器承载着信息网络与用户需求…...
绝对不能错过这份沃尔玛实用插件工具大全
龙哥最近发现很多跨境卖家都比较少运营沃尔玛这个平台。沃尔玛除了是世界500强之外,它的线上商城也弄得很好。它的电商平台主要是售卖自营的,然后你也可以入驻来卖自己的产品,就像是我们国内的京东一样。今天龙哥就给大家分享一些沃尔玛专用插…...
【Java】字符串模板拼接的方法
引 在Java中,构建字符串是非常常见的操作。在很多时候,我们都需要使用变量或输入来定制一个文本输出,例如打印日志、生成HTML代码或构建错误消息。而当需要进行字符串连接时,字符串模板是一种常用的方法。在本篇博客中࿰…...
Vue3项目中使用ECharts图表并实现自适应效果
文章目录 一、Vue3项目安装ECharts二、引入、使用ECharts1.创建图表组件,并在父组件中引入使用2.引入ECharts3.ECharts图表自适应 总结 一、Vue3项目安装ECharts 在项目中输入如下代码: npm install echarts --save安装完成可以在package.json中看到&a…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
