Bean 作用域与生命周期

目录

1.案例

2.作用域

[2.1 Bean 作用域类型](#2.1 Bean 作用域类型)

[2.2 设置作用域](#2.2 设置作用域)

[3.Bean 的生命周期](#3.Bean 的生命周期)

[3.1 Spring 生命周期](#3.1 Spring 生命周期)

[3.2 Bean 的生命周期](#3.2 Bean 的生命周期)


在 Spring 中 Bean 是最核心的操作,接下来我们来分析 Bean 作用域的问题

1.案例

现在有一个公共 Bean(默认是单例模式)的 User 类:

java 复制代码
@Component
public class Users {
    @Bean(name = "user")
    @Scope("prototype") //作用域
    public User getUser() {
        User user = new User();
        user.setId(5);
        user.setName("小温");
        return user;
    }
}

A 用户进行了修改操作(UserController1 类):

java 复制代码
@Controller
public class UserController1 {
    @Autowired
    private User user;

    public void doMethod() {
        User user2 = user;
        System.out.println("UserController1 修改之前:User -> " + user);
        user2.setName("三三");
        System.out.println("UserController1 修改之后:User -> " + user);
    }
}

B 用户使用公共 Bean(UserController2 类):

java 复制代码
@Controller
public class UserController2 {
    @Autowired
    private User user;

    public void doMethod() {
        System.out.println("UserController2 :User -> " + user);
    }
}

打印 A 用户和 B 用户公共 Bean 的值:

java 复制代码
public class App {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        UserController1 userController1 = context.getBean("userController1", UserController1.class);
        userController1.doMethod();

        UserController2 userController2 = context.getBean("userController2", UserController2.class);
        userController2.doMethod();
    }
}

此时我们发现 B 用户打印的是修改后的值:因为 Bean 默认情况下是单例状态(singleton),也就是所有人使用的都是同⼀个对象,之前我们学单例模式的时候都知道,使用单例可以很大程度上提高性能,所以在 Spring 中 Bean 的作用域默认也是 singleton 单例模式。

2.作用域

Bean 的作用域是指 Bean 在 Spring 整个框架中的某种行为模式。 比如 singleton 单例作用域,就表示 Bean 在整个 Spring 中只有⼀份,它是全局共享的,那么当其他人修改了这个值之后,那么另一个人读取到的就是被修改的值。

2.1 Bean 作用域类型

1️⃣singleton 单例模式(默认的作用域)

该作用域下的 Bean 在 IoC 容器中只存在一个实例:获取 Bean(即通过 applicationContext.getBean等方法获取)及装配 Bean 都是同⼀个对象

单例模式的 Bean 是线程安全的吗? 不是(所有人都可以进行操作),使用 ThreaddLocal(本地线程变量)

2️⃣prototype:原型作用域(多例作用域)

每次对该作用域下的 Bean 的请求都会创建新的实例:获取Bean(即通过 applicationContext.getBean 等方法获取)及装配 Bean(即通过@Autowired 注入)都是新的对象实例

3️⃣request:请求作用域

每次http请求会创建新的Bean实例,类似于prototype;只适用于 Spring MVC 项目(Spring Web)

4️⃣session:会话作用域

在⼀个http session中,定义⼀个Bean实例;⽤户回话的共享Bean, 比如:记录⼀个⽤户的登陆信息;只适用于 Spring MVC 项目(Spring Web)

5️⃣application:应用作用域

在⼀个http servlet Context中,定义⼀个Bean实例;只适用于 Spring MVC 项目(Spring Web)

6️⃣websocket:websocket 作用域,只适用于 websocket 作用域(了)

2.2 设置作用域

使用 @Scope 标签声明 Bean 的作用域

1️⃣@Scope("prototype")

2️⃣@Scope("ConfigurableBeanFactory.SCOPE_PROTOTYPE")

3.Bean 的生命周期

3.1 Spring 生命周期

  1. 启动容器
  2. 读取配置进行 Bean 的实例化
  3. 将 Bean 加入到容器中
  4. 装配 Bean 属性(给当前类的属性 DI,进行赋值)
  5. 使用项目,执行 Spring 的相关业务代码
  6. 释放 Bean,销毁 Bean
  7. 关闭容器

3.2 Bean 的生命周期

  1. 实例化(给 Bean 分配内存空间)
  2. 设置 Bean 属性(进行依赖注入,将依赖的 Bean 赋值到当前类的属性上)
  3. Bean 的初始化:1️⃣执行各种通知( 如 BeanNameAware的接口方法**)2️⃣** 初始化的前置方法 BeanPostProcessor3️⃣ 初始化方法 @PostConstruct 4️⃣ 初始化的后置方法 BeanPostProcessor
  4. 使用 Bean
  5. 销毁 Bean :销毁容器的各种方法,如 @PreDestroy、DisposableBean 接口方法、destroy-method。

示例:

java 复制代码
public class BeanLifeComponent implements BeanNameAware {
    @Override
    public void setBeanName(String s) {
        System.out.println("执行了 BeanNameAware -> " + s);
    }

    //初始化方法------注解
    @PostConstruct
    public void doPostConstruct() {
        System.out.println("执行了 @PostConstruct");
    }

    //初始化方法------xml
    public void myInit() {
        System.out.println("执行了 myinit");
    }

    @PreDestroy
    public void doPreDestroy() {
        System.out.println("执行了 @PreDestroy");
    }

    public void sayHi() {
        System.out.println("使用 Bean");
    }
}

xml 配置:

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="spring.java.demo"></content:component-scan>
    <bean id="mybean" class="BeanLifeComponent" init-method="myInit"></bean>
</beans>

测试类:

java 复制代码
public class BeanLifeTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        BeanLifeComponent component = context.getBean("mybean", BeanLifeComponent.class);
        component.sayHi();
        context.close();
    }
}
相关推荐
starzy19906 分钟前
Flink Task 调度任务深度剖析:从调度策略到故障恢复的完整链路
java·大数据·flink
考虑考虑9 分钟前
JFROG手动上传包
运维·后端·自动化运维
开开心心_Every13 分钟前
文件查重软件批量删除重复文件释放空间
java·开发语言·c#·计算机外设·ocr·excel·perl
Wang's Blog19 分钟前
Java 项目实战: 交友项目 - 技术架构与选型剖析
java·架构·交友
我是大猴子20 分钟前
一些八股和限流措施
java
认真的小羽❅29 分钟前
ThreadLocal 在虚拟线程间要小心
java·开发语言·jvm
美味蛋炒饭.35 分钟前
Java八股面试(4)
java·开发语言·面试
SL_staff37 分钟前
OKR落地难?技术团队如何用五层联动链打通执行断层
java·开源·全栈
省钱兄--zs37 分钟前
无人自助拼豆系统架构设计与功能实现落地部署全流程实战指南
java·数据仓库·spring boot·系统架构·需求分析
Raas10038 分钟前
AI网关能做调用审计吗?MAI Gateway(魔芋企业级AI网关)实战能力深度解读
java·服务器·网络·数据库·gateway·prompt·企业级产品