Bean作用域和生命周期
小王学习录
前言
在之前的文章中我们知道, Spring是一个存放Bean的IoC容器, 这个容器的两大核心功能是存Bean和取Bean. 今天来详细了解一下Bean的作用域和生命周期.
Bean的作用域
什么是Bean的作用域
以前我们接触到的作用域说的是变量的可作用范围. 而今天要讲到Bean的作用域不同于之前的作用域, Bean的作用域说的是一个Bean在整个Spring框架中的行为模式. 行为模式有六种. 也就是作用域有六种. 下面将具体介绍这六种行为模式(作用域).
Bean的六种作用域
1. 单例作用域 singleton
singleton单例作用域, 顾名思义. 单例作用域就是在Spring框架中只存有该Bean的一个实例. 在整个框架中对该Bean的注入操作都是同一个对象.
这种作用域是Spring默认的Bean作用域, 适合于无状态的Bean. 所谓无状态就是该Bean的属性对象不需要更新.
当向Spring中存入一个Bean时, Spring默认这个Bean的作用域就是单例的, 因此不需要另外显式配置.
2. 原型作用域 prototype (多例作用域)
prototype多例作用域, 在每次获取Bean(ApplicationContext或通过注解进行注入)时, 都会获取到一个新的实例对象. 该实例对象遵循Spring框架对其进行的初始化操作(@Bean进行初始化).
实际上, 在每次获取实例对象时, 都是通过拷贝一份已有的原型对象实现的.
这种作用域适用于有状态的Bean. 需要注意的是, 这种作用域只适用于Spring框架, 对于Spring MVC和Spring Boot来说是不支持的.
当向Spring中存入一个Bean, 并且要将这个Bean的作用域设置为原型作用域时, 需要用到@Scope("prototype")
或者@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class UserService {
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Bean
public User setUser(){
User user = new User();
user.setUserid(2);
user.setUsername("张三");
user.setPassword("123");
return user;
}
}
3. 请求作用域 request
在每此http请求时会生成一个新的实例. 本此请求和响应公用一个实例. 适用于需要在同一次请求处理期间共享数据的Bean, 确保每个请求都有自己的实例. 在Spring MVC和Spring Boot中使用, Spring中不能使用.
使用时需要用到@RequestScope
4. 会话作用域 session
每个Http会话会创建一个实例, 该实例在整个会话中有效. 适用于在整个会话期间内共享数据的Bean. 在Spring MVC中使用, 在Spring中不能使用.
使用时需要用到@SessionScope
注解.
5. 全局作用域 application
在整个web应用程序中共享一个Bean, 和单例模式相似但不同.
不同之处在于全局作用域是在整个web应用程序中共享一个Bean, 他是Spring Web中的作用域, 作用于Servlet容器.
而单例模式是在整个Spring容器中共享一个Bean. 是Spring中的作用域, 作用于IoC容器.
6. Http WebSocket作用域 websocket
在一个http webSocket的生命周期中定义一个Bean实例. 仅适用于Spring WebSocket中使用.
Spring的执行流程和Bean的生命周期
Spring的执行流程
Bean的执行流程是从启动Spring容器 ->初始化Bean -> 将Bean注册到Spring中 -> 将Bean装配到需要的类中.
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Spring-Config.xml");
UserController controller1 = context.getBean("userController", UserController.class);
controller1.setUser();
UserController2 controller2 = context.getBean("userController2", UserController2.class);
controller2.print();
}
}
- 启动Spring容器: 当代码执行到main方法中的
ApplicationContext context = new ClassPathXmlApplicationContext("Spring-Config.xml");
时, 启动Spring容器. 加载指定的配置文件. - 初始化Bean: 初始化Bean, 就是根据配置文件中指定的要扫描的路径进行扫描, 查找五大类注解和@Bean方法注解. 如果扫描到有需要存到Spring中的Bean, 先实例化(分配内存空间), 然后进行初始化.
- 注册Bean对象到容器中. 这就是往Spring中存Bean对象.
- 将Bean装配到需要的类中, 这就是注入Bean对象.
Bean的生命周期
生命周期是一个对象从诞生到销毁的整个生命过程, 这个过程就叫做一个对象的生命周期.
Bean的生命周期分为以下五步:
1. 实例化Bean
为Bean分配内存空间
2. 设置属性
将当前Bean所依赖的Bean注入进来. 为当前Bean的初始化做准备.
3. Bean初始化
- 发送通知: 继承一些通知接口, 如BeanNameAware, BeanFactoryAware, ApplicationContextAware. 实现这些接口的方法
public class Bean implements BeanNameAware, BeanFactoryAware {
@Override
public void setBeanName(String s) {
System.out.println("通知bean名为 -> " + s);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("通知工厂bean为 -> " + beanFactory);
}
}
- 执行初始化的前置方法: 通过实现
BeanPostProcessor
接口, 重写postProcessBeforeInitialization
方法. 前置方法和后置方法都不用显式调用
这个方法在Bean的初始化方法调用之前被调用. 实现BeanPostProcessor
接口并覆写该方法, 可以在Bean初始化之前进行一些自定义的操作. 例如, 对Bean的属性进行修改或验证等.
public class Bean implements BeanNameAware, BeanFactoryAware , BeanPostProcessor {
@Override
public void setBeanName(String s) {
System.out.println("通知bean名为 -> " + s);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("通知工厂bean为 -> " + beanFactory);
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("执行初始化前置方法");
return bean;
}
}
- 执行初始化方法: 可以在xml文件中配置, 或者也可以通过注解@PostConstruct. 两者都出现时, 通过注解的方式优先级更高.
(1) 通过xml文件:
<bean id="bean" class="com.annotation.controller.Bean" init-method="beanInit"
destroy-method="destory"> </bean>
public void beanInit(){
System.out.println("通过xml初始化bean");
}
(2) 通过注解@PostConstruct:
@PostConstruct
public void beanInit2(){
System.out.println("通过注解初始化bean");
}
- 执行初始化的后置方法
这个方法在Bean的初始化方法调用之后被调用. 和前置方法一样实现BeanPostProcessor
接口, 重写后置方法postProcessAfterInitialization
, 可以在Bean初始化之后进行一些自定义的操作. 例如, 对Bean进行额外的初始化或修改.
public class Bean implements BeanNameAware, BeanFactoryAware , BeanPostProcessor {
@Override
public void setBeanName(String s) {
System.out.println("通知bean名为 -> " + s);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("通知工厂bean为 -> " + beanFactory);
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("执行初始化前置方法");
return bean;
}
public void beanInit(){
System.out.println("通过xml初始化bean");
}
@PostConstruct
public void beanInit2(){
System.out.println("通过注解初始化bean");
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("执行初始化后置方法");
return bean;
}
}
4. 使用Bean
public void print(){
System.out.println("使用bean");
}
5. 销毁Bean
销毁Bean的方法与初始化Bean的方法类似, 可以在xml中配置, 也可以通过注解. 与初始化bean不同的是, bean的初始化方法无需显式调用, 而bean的销毁方法需要显式调用.
(1) 通过xml配置
<bean id="bean" class="com.annotation.controller.Bean" init-method="beanInit"
destroy-method="destory"> </bean>
public void destory(){
System.out.println("通过xml销毁bean");
}
(2) 通过注解@PreDestroy
@PreDestroy
public void destory2(){
System.out.println("通过注解销毁bean");
}
代码汇总:
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:context="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">
<context:component-scan base-package="com.annotation"></context:component-scan>
<bean id="bean" class="com.annotation.controller.Bean" init-method="beanInit"
destroy-method="destory" scope="prototype"> </bean>
</beans>
Bean类:
public class Bean implements BeanNameAware, BeanFactoryAware, BeanPostProcessor{
@Override
public void setBeanName(String s) {
System.out.println("通知bean名为 -> " + s);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("通知工厂bean为 -> " + beanFactory);
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("执行初始化前置方法");
return bean;
}
public void beanInit(){
System.out.println("通过xml初始化bean");
}
@PostConstruct
public void beanInit2(){
System.out.println("通过注解初始化bean");
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("执行初始化后置方法");
return bean;
}
public void destory(){
System.out.println("通过xml销毁bean");
}
@PreDestroy
public void destory2(){
System.out.println("通过注解销毁bean");
}
public void print(){
System.out.println("使用bean");
}
}
Main类:
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Spring-Config.xml");
// UserController controller1 = context.getBean("userController", UserController.class);
// controller1.setUser();
// UserController2 controller2 = context.getBean("userController2", UserController2.class);
// controller2.print();
Bean bean = context.getBean("bean", Bean.class);
bean.print();
bean.destory();
bean.destory2();
}
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!