关于bean 的作用域

69 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第14天,点击查看活动详情

Bean 的介绍

Spring Bean 是 Spring IOC 容器在运行时管理的对象。Spring Bean 是 Spring 程序中不可或缺的一部分。如果将 Spring 看做一个大型工厂的话,那么 Bean 就是这个工厂中的产品。如果要想让这个工厂来生产和管理 Bean ,就需要在配置文件中告诉它需要哪些 Bean,以及如何组装这些 Bean。这里所说的 Bean 本质就是 Java 中的类。

下面是配置文件中一个 bean 标签中所涉及到的属性,如下表所示 :

属性描述
class这个属性是强制性的,并且指定用来创建 bean 的 bean 类。
id这个属性指定唯一的 bean 标识符。在基于 XML 的配置元数据中,你可以使用 id 或 name 属性来指定 bean 标识符。
scope这个属性指定由特定的 bean 定义创建的对象的作用域。
constructor-arg它是用来注入依赖关系的
properties它是用来注入依赖关系的
autowiring mode它是用来注入依赖关系的
lazy-initialization mode延迟初始化的 bean 告诉 IoC 容器在它第一次被请求时,而不是在启动时去创建一个 bean 实例。
initialization 方法在 bean 的所有必需的属性被容器设置之后,调用回调方法。
destruction 方法当包含该 bean 的容器被销毁时,使用回调方法。

Bean 的作用域

默认情况下,Spring 只会为 IOC 容器中声明的 Bean 创建一个实例,并且这个实例是在整个 IOC 容器范围内都能共享的,所以后续的对象通过 getBean() 方法调用和 Bean 的引用都将返回这个唯一的实例。假如我们现在需要不同的实例 Bean ,我们该如何处理呢?

这就设计到 Bean 的作用域了。还记得前面加粗的属性 scope 吗,它就是用来指定 Bean 的作用域的。默认情况下,scope 的值为 Singleton,表示单例。在 Spring 中提供了 6 种作用域,如下表所示 :

作用域描述
singleton单例模式(默认) ,实例化的 Bean 在整个 Spring IOC 容器生命周期中只创建一次,单个 Bean 被绑定到单个对象实例。
prototype多例模式,Spring IOC 容器初始化时不创建 Bean 的实例,而是在通过 getBean 获取 Bean 时才会创建一个新的 Bean 实例并返回, 单个 Bean 定义可以被绑定到多个对象实例。
request单个 Bean 定义被绑定到单个的 HTTP 请求生命周期。就是每一个 HTTP 请求都有属于他自己的单独实例创建,这个只能在 web-aware Spring ApplicationContext 中有效。
session单个 Bean 定义会被绑定到 HTTP Session 的生命周期中,这个只能在 web-aware Spring ApplicationContext 中有效。
application单个 Bean 定义会被绑定到 ServletContext 的生命周期中,这个只能在 WebApplicationContext 中有效。
websocket单个 Bean 的定义会被绑定到 WebSocket 的生命周期中,这个只能在 WebApplicationContext 中有效。

上述几种作用域,在实际开发中 singleton 和 prototype 值最常用的两种。

1. singleton

a. 在 applicationContextByName.xml 配置文件中配置 Employee 这个 JaveBean,并指定 scope="singleton",如下所示
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="employee" class="com.yamiya.pojo.Employee" scope="singleton">

    </bean>


</beans>

说明:scope 是用来设置作用域的,如果不写,默认也是 singleton,表示单例。

b.在测试类 SpringTest 中添加测试方法,代码如下:
@Test
public void test1() throws IOException{
  Employee e1 = context.getBean("employee",Employee.class);
  Employee e2 = context.getBean("employee",Employee.class);
  Employee e3 = context.getBean("employee",Employee.class);
  System.out.println(e1);
  System.out.println(e2);
  System.out.println(e3);
}

image.png

分析:观察上图可以发现,虽然调用三次 getBean 方法获取了三个实例对象,但是三个实例对象的地址都是一样的,也就是说这三个实例对象实际是同一个实例对象。这就是单例模式(singleton),它是在 Bean 整个生命周期内只被创建一次,创建好了之后,它在整个 IOC 容器中是被共享的。

2. prototype

a. 将配置文件中的作用域改为 scope="prototype",代码如下

b. 测试代码不变,直接点击进行测试,结果如下图所示

image.png

分析:观察上图可以发现,调用三次 getBean 方法获取了三个实例对象,三个实例对象的地址都不一样,也就是说分别创建了三个实例对象。这就是多例模式(prototype),实例对象是在调用 getBean 方法时才会被创建,每调用一次 getBean 方法获取的实例化对象都不一样。

总结

Spring Bean 作用域,重点是以下两种作用域:

  • singleton:表示单例(默认)模式

    实例化的 Bean 在整个 Spring IOC 容器生命周期中只创建一次,单个 Bean 被绑定到单个对象实例

  • prototype:表示多例模式

    Spring IOC 容器初始化时不创建 Bean 的实例,而是在通过 getBean 获取 Bean 时才会创建一个新的 Bean 实例并返回, 单个 Bean 定义可以被绑定到多个对象实例。