Spring Bean 的作用域和生命周期
1. Bean 的作用域
1.1 什么是 Bean 的作用域?
Bean
的作用域是指 Bean
在 Spring
整个框架中的某种行为模式,Bean
的作用域用于定义 在IoC
容器中创建的Bean
实例的生命周期范围。
案例:我们创建如下的类
User: @Getter
、@Setter
、@ToString
是 Lombok
插件以及依赖提供,我们就不用写get
、set
、toSpring
方法了(怎么配置,后文介绍)。
@Getter
@Setter
@ToString
public class User {
private int id;
private String name;
}
UserBeans:
@Component
public class UserBeans {
//创建一个Bean,并把它放入Spring容器中。
@Bean
public User user(){
User user = new User();
user.setId(1);
user.setName("小明");
return user;
}
}
UserController:
@Controller
public class UserController {
@Autowired
private User user;//注入User,此时 User 是“小明”
public void print(){
System.out.println("user--> " user);
//修改 myUser
User myUser = user;
myUser.setName("张三");
System.out.println("myUser--> " myUser);
System.out.println("user--> " user);
}
}
UserController2:
@Controller
public class UserController2 {
@Autowired
private User user;//注入
public void print(){
System.out.println("user--> " user);//目的:想得到“小明”
}
}
Main:
public class Main {
public static void main(String[] args) {
//获取Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
UserController userController = context.getBean("userController",UserController.class);
userController.print();
System.out.println("------------------------------------------------------------------------");
UserController2 userController2 = context.getBean("userController2", UserController2.class);
userController2.print();
}
}
结果:
可以看到,User
在全局下是同一个对象,换言之,此处的Bean
在Spring
容器中只有一份。在任何一个地方修改此处的Bean
,它的值就会改变;但是我们预期的结果是,公共 Bean
可以在各自的类中被修改,但不能影响到其他类,显然上面的代码违背了我们的预期,这就是作用域的体现。
1.1.1 Lombok 的配置
第一步:将下面的代码赋值到pom.xml文件中
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<scope>provided</scope>
</dependency>
第二步:在插件商店中下载“Lombok”
第三步:加注解
注解名称 | 作用 |
---|---|
@Getter |
自动生成 getter 方法 |
@Setter |
自动生成 setter 方法 |
@ToString |
自动生成 toString() 方法 |
@EqualsAndHashCode |
自动生成 equals() 和 hashCode() 方法 |
@NoArgsConstructor |
自动生成无参构造函数 |
@AllArgsConstructor |
自动生成包含所有参数的构造函数 |
@RequiredArgsConstructor |
自动生成包含必需参数的构造函数 |
@Data |
自动生成 toString() 、equals() 、hashCode() 、getter 和 setter 方法 |
1.2 Bean 的 6 种作用域
-
Singleton:
单例作用域(默认),整个应用中只有一个 Bean 实例,每次请求时都返回同一个实例。 -
Prototype:
原型作用域,每次请求时都会创建一个新的 Bean 实例,即每次使用该 Bean 时,Spring 都会创建一个新的实例。 -
Request:
请求作用域,每次 HTTP 请求都会创建一个新的 Bean 实例,该作用域仅适用于 WebApplicationContext 环境。 -
Session:
会话作用域,每个 HTTP Session 都会创建一个新的 Bean 实例,该作用域仅适用于 WebApplicationContext 环境。 -
Application:
应用作用域,整个应用程序中只有一个 Bean 实例,该作用域仅适用于 ServletContext 环境。 -
WebSocket:
WebSocket 作用域,每个 WebSocket 连接都会创建一个新的 Bean 实例,该作用域仅适用于 WebApplicationContext 环境。
需要注意的是,Request
、Session
和 WebSocket
这三种作用域只适用于 WebApplicationContext(Spring MVC)
环境,即只能在 Web
应用程序中使用。而 Singleton
、Prototype``` 和 ``Application
三种作用域适用于所有环境。
(后 4 种状态是 Spring MVC 中的值,在普通的 Spring 项⽬中只有前两种)
1.3 自定义作用域
还是用上面的案例,自定义作用域要用到@Scope
注释,我们要在 Bean
存入容器的位置设置:
@Component
public class UserBeans {
//@Scope("prototye") 也可以这么写。
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)//设置为 Prototype 模式
@Bean
public User user(){
User user = new User();
user.setId(1);
user.setName("小明");
return user;
}
}
结果:
现在已经成功了。
2. Bean 的生命周期
2.1 Spring 的执行流程
这里仅了解大概的流程:
启动 Spring 容器 -> 实例化 Bean -> Bean 注册到 Spring 中 -> 将 Bean 装配到需要的类中(注入)。
2.2 Bean 的生命周期
在Spring框架中,一个Bean的生命周期可以分为以下几个阶段:
- 实例化 Bean:当Spring容器加载配置文件并初始化时,它会根据Bean定义创建Bean的实例。
- 属性赋值:容器会将Bean的属性注入到相应的属性中,这些属性可能是基本类型、集合或其他Bean。
- Bean 初始化
- 各种通知:实现了各种 Aware 通知的⽅法,如 BeanNameAware、BeanFactoryAware、 ApplicationContextAware 的接口⽅法;
- 执行初始化前置方法;
- 执行初始化方法;
- 注解方式:@PostConstruct
- xml方式:init-method 方法
- 执行初始化后置方法;
- 使用 Bean
- 销毁 Bean:如果 Bean 实现了 DisposableBean 接口,容器将调用它的 destroy() 方法;或者 Bean 可以定义一个自定义销毁方法(xml方式),使用 destroy-method 属性指定该方法;或者用 @PreDestroy 注释的方法。
前置方法和后置方法通常是指实现了 BeanPostProcessor 接口的类中的方法。具体来说,BeanPostProcessor接口定义了两个方法:postProcessBeforeInitialization() 和postProcessAfterInitialization()。前者在Bean初始化之前调用,后者在Bean初始化之后调用。
2.3 通过案例来看生命周期
我们创建如下的类。
spring-config.xml:
<?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.spring.demo.component"></content:component-scan>
<!-- 这里用了 init-method="init" 来指定初始化方法 -->
<bean id="beanComponent" class="com.spring.demo.component.BeanComponent" init-method="init"></bean>
</beans>
BeanComponent:
public class BeanComponent implements BeanNameAware {
//通知方法
@Override
public void setBeanName(String s) {
System.out.println("执行了通知 BeanName: " s);
}
//初始化方法(用xml的方式)
public void init(){
System.out.println("用xml的方式->初始化方法");
}
//用注释的方式初始化方法
@PostConstruct
public void doPostConstruct(){
System.out.println("用注释的方式->初始化方法");
}
public void hi(){
System.out.println("执行了hi()->Hello!");
}
//销毁 用注释的方式
@PreDestroy
public void doPreDestroy(){
System.out.println("销毁:doPreDestroy");
}
}
Main:
public class Main {
public static void main(String[] args) {
//为什么是 ClassPathXmlApplicationContext? 因为它提供了destroy方法。
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
BeanComponent beanComponent = context.getBean("beanComponent",BeanComponent.class);
//调用hi方法
beanComponent.hi();
//销毁 Bean 对象
context.destroy();
}
}
结果:
(ps:如有错误,请在评论区指出,谢谢🌹)
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhbebbgh
-
photoshop蒙版画笔没反应怎么办
PHP中文网 06-24 -
微信小程序没声音怎么办
PHP中文网 06-15 -
excel图片置于文字下方的方法
PHP中文网 06-27 -
微信提示登录环境异常是什么意思原因
PHP中文网 04-09 -
微信运动停用后别人还能看到步数吗
PHP中文网 07-22 -
微信人名旁边有个图标有什么用
PHP中文网 03-11 -
使用云服务器搭建个人游戏加速器教程
AuroraJay 07-06 -
Excel筛选和排序是灰色的怎么办
PHP中文网 06-22 -
抖音国际版要用什么加速器能流畅刷Tiktok的加速器
TK小达人 08-02 -
键盘上的负数是哪个键
PHP中文网 03-17