Bean的作用域
一般情况下,我们书写在IOC容器中的配置信息,会在我们的IOC容器运行时被创建,这就导致我们通过IOC容器获取到bean对象的时候,往往都是获取到了单例的Bean对象。
这样就意味着无论我们使用多少个 getBean()方法,获取到的同一个 JavaBean 都是同一个对象,这就是单实例 Bean,整个项目都会共享这一个 bean 对象。
在 Spring 中,可以在元素的 scope 属性里设置 bean 的作用域,以决定这个 bean 是单实例的还是多实例的。
Spring 框架支持以下五个作用域,分别为 singleton、prototype、request、session 和 global session,5种作用域说明:
- singleton:在spring IOC容器仅存在一个Bean实例,Bean以单例方式存在,默认值
- prototype:每次从容器中调用Bean时,都会返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()
- request:每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
- session:同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境
- global-seesion:一般用于Protlet应用环境,该作用域仅适用于WebApplicationContext环境
singleton 作用域:
singleton 是默认的作用域,也就是说,当定义 Bean 时,如果没有指定作用域配置项,则 Bean 的作用域被默认为 singleton。
当一个bean的作用域为 Singleton,那么 Spring IoC 容器中只会存在一个共享的 bean 实例,并且所有对 bean 的请求,只要 id 与该 bean 定义相匹配,则只会返回 bean 的同一实例。
也就是说,当将一个 bean 定义设置为 singleton 作用域的时候,Spring IoC 容器只会创建该 bean 定义的唯一实例。
Singleton 是单例类型,就是在创建起容器时就同时自动创建了一个 bean 的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton 作用域是 Spring 中的缺省作用域。你可以在 bean 的配置文件中设置作用域的属性为 singleton,如下所示:
1 | <!-- A bean definition with singleton scope --> |
prototype 作用域
当一个 bean 的作用域为 Prototype,表示一个 bean 定义对应多个对象实例。Prototype 作用域的 bean 会导致在每次对该 bean 请求(将其注入到另一个 bean 中,或者以程序的方式调用容器的 getBean() 方法)时都会创建一个新的 bean 实例。Prototype 是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的 bean 应该使用 prototype 作用域,而对无状态的bean则应该使用 singleton 作用域。
为了定义 prototype 作用域,你可以在 bean 的配置文件中设置作用域的属性为 prototype,如下所示:
1 | <!-- A bean definition with singleton scope --> |
Bean 的生命周期
bean的初始和销毁
在IOC中创建的每一个bean对象都是有其特定的生命周期的,在Spring的IOC容器中可以管理bean的生命周期,Spring允许在bean生命周期内待定的时间执行指定的任务。
Spring IOC容器对bean的生命周期进行管理的过程可以分为:
- 通过构造器或工厂方法创建bean 实例
- 为bean的属性设置值和对其他bean的引用
- 调用bean的初始化方法
- bean可以正常使用
- 当容器关闭时,调用bean的销毁方法
1 | package com.spring.beans; |
这时我们在配置 bean 时,可以通过 init-method 和 destroy-method 属性为 bean 指定初始化和销毁方法
1 | <!-- 设置bean的生命周期 |
这样当我们在通过 IOC 容器创建和销毁 bean 对象时就会执行相应的方法
但是这里还是有一点需要注意:
我们上面说了,单实例的 bean 和多实例的 bean 的创建时间是不同的,那么他们的初始方法和销毁方法的执行时间就稍稍有不同。
单实例下 bean 的生命周期
容器启动——>初始化方法——>(容器关闭)销毁方法
多实例下 bean 的生命周期
容器启动——>调用 bean——>初始化方法——>容器关闭(销毁方法不执行)
bean 的后置处理器
什么是 bean 的后置处理器?bean 后置处理器允许在调用初始化方法前后对 bean 进行额外的处理
bean 后置处理器对 IOC 容器里的所有 bean 实例逐一处理,而非单一实例。
其典型应用是:检查 bean 属性的正确性或根据特定的标准更改 bean 的属性。
bean 后置处理器使用时需要实现接口:
org.springframework.beans.factory.config.BeanPostProcessor。
在初始化方法被调用前后,Spring 将把每个 bean 实例分别传递给上述接口的以下两个方法:
postProcessBeforeInitialization(Object, String)调用前
postProcessAfterInitialization(Object, String)调用后
如下是一个实现在该接口的后置处理器:
1 | package com.spring.beans; |
将该后置处理器加入到 IOC 容器中:
1 | <!-- 测试bean的后置处理器 --> |
由于现在我们的 bean 对象是单实例的,所以容器运行时就会直接创建 bean 对象,同时也会执行该 bean 的后置处理器方法和初始化方法,在容器被销毁时又会执行销毁方法。我们测试如下:
1 | //*************************bean生命周期***************** |
运行结果:
总结一下后置处理器的执行过程:
通过构造器或工厂方法创建 bean 实例
为 bean 的属性设置值和对其他 bean 的引用
将 bean 实例传递给 bean 后置处理器的**postProcessBeforeInitialization()**方法
调用 bean 的初始化方法
将 bean 实例传递给 bean 后置处理器的**postProcessAfterInitialization()**方法
bean 可以使用了
当容器关闭时调用 bean 的销毁方法
所以添加 bean 后置处理器后 bean 的生命周期为:
容器启动——后置处理器的 before…——>初始化方法——>后置处理器的 after…———>(容器关闭)销毁方法