Bean 的作用域和生命周期

简介: 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);
    }
}


输出结果:


78628847231d4f5f81a504c75146fecf.png


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


我们在最初的时候,设计一个 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;
    }
}


输出结果:


d062a1bbcc1f4bfd91d43e2d1362e703.png


在原型模式下,获取 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


9f28e03081284bc5886f7260c13dc3c7.png


例子


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


  1. 先买房(实例化,从无到有)
  2. 装修(设置属性)
  3. 买家电,如洗衣机、冰箱、电视、空调等([各种]初始化)
  4. 入住(使用 Bean)
  5. 卖出去(Bean 销毁)


目录
相关文章
|
4月前
|
前端开发 Java 开发者
Bean的生命周期和作用域
Bean的生命周期和作用域
|
4月前
|
XML Java 数据格式
Spring框架学习 -- Bean的生命周期和作用域
Spring框架学习 -- Bean的生命周期和作用域
41 2
|
4月前
|
存储 设计模式 Java
Bean 作用域和生命周期
Bean 作用域和生命周期
|
前端开发 Java C++
Bean的作用域
Bean 常见的 6 种作用域
|
Java 容器 Spring
Bean生命周期
Bean生命周期
|
4月前
|
Java 开发者 Spring
Bean 的生命周期了解么
Bean 的生命周期了解么
|
9月前
|
Java Spring 容器
bean的生命周期
bean的生命周期
45 0
|
存储 安全 Java
Bean 的作用域和生命周期
Bean 的作用域和生命周期
59 1
|
11月前
|
Java 容器 Spring
bean的作用域和生命周期和后置处理器以及作用域对生命周期的影响~
bean的作用域和生命周期和后置处理器以及作用域对生命周期的影响~
|
XML Java 数据格式
Bean 的生命周期
Bean 的生命周期介绍