Bean 的作用域和生命周期

引言

在实际工作中或者日常做项目的时候,我们都会更加注重 " 如何使用 spring 框架 ",也就是将核心放在 【存 / 取 spring 中的对象】这件事情上。

然而,如果我们需要更加深入理解一个 bean 对象 " 在存取的过程中发生了什么 ",就需要明白它的作用域和生命周期。

一、Bean 的作用域

引入案例

User 类:

public class User{
    public int id;
    public String name;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

UserBean 类,用来往 spring 中存放 User对象。

@Controller
public class UserBean {
    @Bean(name = "user3")
    public User getUser3() {
        User user = new User();
        user.id = 3;
        user.name = "小明";
        return user;
    }
}

BeanScpoe1 类,进行 user3 对象注入,之后拿一个新的 user 对象接收。

@Component
public class BeanScope1 {
    @Autowired
    private User user3;

    public User hello() {
        User user = user3;
        user.name = "小红";
        return user;
    }
}

BeanScope2 类,进行 user3 对象注入。

@Component
public class BeanScope2 {

    @Autowired
    private User user3;

    public User hello() {
        return user3;
    }
}

Run 启动类:

public class Run {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        BeanScope1 beanScope1 = context.getBean( "beanScope1", BeanScope1.class);
        User user = beanScope1.hello();
        System.out.println( " beanScope1: " + user);

        BeanScope2 beanScope2 = context.getBean("beanScope2", BeanScope2.class);
        User user2 = beanScope2.hello();
        System.out.println(" beanScope2: " + user2);
    }
}

输出结果:

1-1

描述一下上述的代码逻辑:

我们在最初的时候,设计一个 User 类,里面放着 " id " 和 " name " 字段;之后,我们预期将 User 类的对象放入 spring 容器中,所以就设计了一个 UserBean 类,最终,我们将 " id = 3 " 和 " name = 小明 " 的对象放入了 spring 容器中,bean 对象名字为 user3.

接着,我们又设计了一个 BeanScpoe1 类,进行了 user3 对象注入,我们期望通过一个新的 user 对象接收,并为新的对象设置 " name = 小红 ",然而,不巧的是,这一操作,直接影响到了 spring 容器中的 user3 对象。

所以,后面我们在 BeanScope2 类,注入 user3 对象的时候,原来 " name = 小明 " 就变成了 " name = 小红 "。

分析原因

造成以上的结果,其原因是 Bean 默认情况下是单例状态,bean 对象只有一个,也就是说,所有类使用的其实是同一个 bean 对象。

而上面的这种单例状态的情况,实际上只是 Bean 作用域的其中一种模式。

Bean 的作用域

Bean 的作用域是指 Bean 在 Spring 整个框架中的某种行为模式。

比如 singleton 单例作用域,就表示 bean 对象在整个 Spring 中只有一份,它是全局共享的,那么当其他人修改了这个值之后,那么另一个人读取到的就是被修改的值。

Bean 的六种作用域

在普通的 Spring 项目中只有 前两种,而 后四种状态是 Spring MVC 中的值。

1. singleton:单例模式 ( 默认 )

单例模式下,获取 bean 对象 / 注入 bean 对象,都是针对于同一个对象。

2. prototype:原型模式 ( 多例模式 )

原型模式实际上和默认的单例模式正好相反。

原型模式下,获取 bean 对象 / 注入 bean 对象,都是新的对象实例。也就是说,每次对该作用域下的 Bean 请求都会创建新的实例。

3. request:请求作用域 ( Spring MVC )

当前模式下,每次 HTTP 请求都会创建新的 bean 对象,类似于 " prototype " ,只不过,此模式限定在 Spring MVC 中使用。

4. session:会话作用域 ( Spring MVC )

在一个 HTTP Session 中,定义一个 bean 对象,这就和之前的 Servlet 提供的会话机制差不多。比方说它用到的一个典型场景:记录一个用户的登录信息。

5. application:全局作用域 ( Spring MVC )

在一个 HTTP Servlet Context 中,定义一个 bean 对象。

6. websocket:HTTP WebSocket作用域 ( Spring WebSocket )

在一个 HTTP WebSocket 中,定义一个 bean 对象。

更改作用域

由于当前的是一个普通的 spring 项目,我们就将 " 单例模式 " 换成 " 原型模式 ",看一下效果。

对于上面的 UserBean 类进行改变,也就是让 User 对象存入 spring 容器时,添加一个 " @Scope " 注解。其他的代码不需要改动。

@Controller
public class UserBean {

    @Bean(name = "user3")
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public User getUser3() {
        User user = new User();
        user.id = 3;
        user.name = "小明";
        return user;
    }
}

输出结果:

1-2

在原型模式下,获取 bean 对象 / 注入 bean 对象,都是新的对象实例。也就是说,BeanScope1 类无论怎么修改,都不影响 BeanScope2 类拿 user3 对象。

格式

// 两种写法
@Scope("prototype")

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

二、Bean 的生命周期

所谓的生命周期指的是一个对象从诞生到销毁的整个生命过程,我们把这个过程就叫做一个 bean 对象的生命周期。

一个 bean 对象的生命周期大致分为下面的五个部分:

1. 实例化 ( 给 bean 分配内存空间 )

2. 设置属性 ( 对象注入 )

3. 初始化

(1) 执行各种通知 ( 执行各种 Aware )
(2) 执行初始化的前置方法
(3) 执行构造方法,两种执行方式,一种是执行 " @PostConstruct " , 另一种是执行 " init-method " .
(4) 执行初始化的后置方法

4. 使用 Bean

5. 销毁Bean

(1) " @PreDestroy "
(2) 重写 DisposableBean 接口方法
(3) destroy - method

2-1

例子

我们可以将一个 bean 对象想象成一个买房到卖房的过程。

  1. 先买房(实例化,从无到有)
  2. 装修(设置属性)
  3. 买家电,如洗衣机、冰箱、电视、空调等([各种]初始化)
  4. 入住(使用 Bean)
  5. 卖出去(Bean 销毁)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十七ing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值