request — 请求作用域
描述🍭
每次 HTTP 请求都会创建一个新的实例
一次 HTTP 的请求和响应共享同一个 Bean
适用场景🍭
在 SpringMVC 中使用
session — 会话作用域
描述🍭
在一个 HTTP Session 中创建一个新的实例
举个栗子🌰
用户 Jack 登录他的账号, 在 Jack 登陆状态中, Bean 处于共享状态(针对于 Jack 的信息)
另一个用户 Tom 登录他的账号, 在 Tom 登陆状态中, Bean 处于共享状态(针对于 Tom 的信息)
对于 Jack 和 Tom, 他们的 Bean 是隔离而非共享
适用场景🍭
在 SpringMVC 中使用
application — 全局作用域
描述🍭
在一个 HTTP Servlet Context 中创建一个新的实例
适用场景🍭
在 SpringMVC 中使用
websocket — HTTP WebSocket 作用域
描述🍭
在一个 HTTP WebSocket 的生命周期中创建一个新的实例
WebSocket 的每次会话中, 保存了一个 Map 结构的头信息, 用于包裹客户端消息头
第一次初始化后, 直到 WebSocket 结束都是同一个 Bean
适用场景🍭
在 SpringMVC 中使用
对比单例作用域与全局作用域
- singleton 是 Spring Core 的作用域
application 是 Spring Web 的作用域 - singleton 作用于 IOC 容器
application 作用于 Servlet 容器
设置作用域
利用 @Scope() 设置作用域
作用域 | 设置方式 |
singleton — 单例作用域 | @Scope("singleton") / @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)) |
prototype — 原型作用域 | @Scope("prototype") / @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) |
request — 请求作用域 | @Scope("request") / @Scope(WebApplicationContext.SCOPE_REQUEST) |
session — 会话作用域 | @Scope("session") / @Scope(WebApplicationContext.SCOPE_SESSION) |
application — 全局作用域 | @Scope("application") / @Scope(WebApplicationContext.SCOPE_APPLICATION) |
以 prototype — 原型作用域 为例
🔎Spring的执行流程
- 启动容器(项目)
- 读取
xml
配置文件, 将 Bean 初始化
- 直接注册 Bean(
<bean id="" class=""></bean>
) - 配置根扫描路径(
<content:component-scan base-package=""></content:component-scan>
)
- 将 Bean 存储至 Spring
- 从 Spring 中读取 Bean
启动容器(项目)
读取xml
配置文件, 将 Bean 初始化
将 Bean 存储至 Spring
从 Spring 中读取 Bean
🔎Bean的生命周期
Bean 的生命周期分为 5 个部分
- 实例化 Bean(为 Bean 分配内存空间)
实例化是一个从无到有的过程, 将字节码转换成内存中的对象, 分配了内存空间 → 类似于 JVM 的加载过程 - 设置属性(Bean 注入)
- 初始化 Bean
- 实现了各种 Aware 的通知方法, 例如 BeanNameAware, BeanFactoryAware…
- 执行 BeanPostProcessor 初始化的前置方法
- 执行 @PostConstruct 初始化方法
- 执行指定的 init-method 初始化方法(如果有)
- 执行 BeanPostProcessor 初始化的后置方法
- 使用 Bean
- 销毁 Bean
对比 @PostConstruct 与 init-method
相同🍭
都是初始化方法
不同🍭
@PostConstruct 使用注解进行初始化
init-method 使用 xml 进行初始化(<bean></bean>
)
执行顺序 @PostConstruct > init-method
对Bean的生命周期的解释
实例化🍂
类似于购买了一套毛坯房
设置属性(Bean 注入)🍂
为毛坯房挑选装修风格, 装修材料(引入外部资源)
Bean 初始化🍂
装修毛坯房
- 实现了各种 Aware 的通知方法🍂
雇用各种装修工人进行装修(水工, 电工, 瓦工…) - 执行 BeanPostProcessor 初始化的前置方法🍂
装修工人到达施工现场, 制定装修方案 - 执行初始化方法🍂
有 2 批装修工人
一批使用现代化装修工具但经验不足(@PostConstruct)
另一批使用传统装修工具但经验充足(init-method)
注解的出现时间对比xml
较晚
优先雇用使用现代化装修工具但经验不足的工人 → 执行顺序 @PostConstruct > init-method - 执行 BeanPostProcessor 初始化的后置方法🍂
完成装修任务的工人做的一些善后工作(清理装修的垃圾…)
使用Bean🍂
购房者搬进装修好的房子
销毁Bean🍂
购房者将房子卖掉
示例
示例代码🍂
package com.demo.component; import org.springframework.beans.factory.BeanNameAware; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; //@Component public class BeanLifeComponent implements BeanNameAware { @Override public void setBeanName(String s) { System.out.println("执行了通知"); } public void init() { System.out.println("执行了 Init-method"); } @PostConstruct public void postConstruct() { System.out.println("执行了 @PostConstruct"); } @PreDestroy public void preDestroy() { System.out.println("执行 PreDestroy — 销毁方法"); }
配置文件🍂
<?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.demo"></content:component-scan> <bean id="myComponent" class="com.demo.component.BeanLifeComponent" init-method="init"></bean> </beans>
示例代码🍂
public static void main(String[] args) { // ClassPathXmlApplicationContext 包含销毁方法 // ApplicationContext 不包含销毁方法 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); BeanLifeComponent lifeComponent = context.getBean("myComponent", BeanLifeComponent.class); System.out.println("使用 Bean"); // 销毁 Bean context.destroy(); }
🔎结尾
创作不易,如果对您有帮助,希望您能点个免费的赞👍
大家有什么不太理解的,可以私信或者评论区留言,一起加油