Bean 的生命周期
Spring 生命周期有四个阶段,分别是:
- 实例化 Instantiation
- 属性赋值 Populate
- 初始化 Initialization
- 销毁 Destruction
实例化
通过构造器或工厂方法创建 Bean 实例,也就是我们常说的给自己 new 一个对象。
属性赋值
为 Bean 的属性设置值和对其他 Bean 的引用,主要涉及以下几个方面的内容:
- IOC 依赖注入:按照 Spring 上下文对实例化的 Bean 进行配置,也就是 IOC 注入;
- setBeanName 实现:如果这个 Bean 已经实现了 BeanNameAware 接口,会调用它实现的 setBeanName(String)方法,此处传递的就是 Spring 配置文件中 Bean 的 id 值;
- BeanFactoryAware 实现:如果这个 Bean 已经实现了 BeanFactoryAware 接口,会调用它实现的 setBeanFactory,setBeanFactory(BeanFactory)传递的是 Spring 工厂自身(可以用这个方式来获取其它 Bean,只需在 Spring 配置文件中配置一个普通的 Bean 就可以);
- ApplicationContextAware 实现:如果这个 Bean 已经实现了 ApplicationContextAware 接口,会调用setApplicationContext(ApplicationContext)方法,传入 Spring 上下文(同样这个方式也可以实现步骤 4 的内容,但比 4 更好,因为 ApplicationContext 是 BeanFactory 的子接口,有更多的实现方法);
- postProcessBeforeInitialization 接口实现-初始化预处理:如果这个 Bean 关联了 BeanPostProcessor 接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor 经常被用作是 Bean 内容的更改,并且由于这个是在 Bean 初始化结束时调用那个的方法,也可以被应用于内存或缓存技术。
初始化
- init-method:如果 Bean 在 Spring 配置文件中配置了 init-method 属性会自动调用其配置的初始化方法;
- postProcessAfterInitialization:如果这个 Bean 关联了 BeanPostProcessor 接口,将会调用postProcessAfterInitialization(Object obj, String s)方法。
注:以上工作完成以后就可以应用这个 Bean 了,那这个 Bean 是一个 Singleton 的,所以一般情况下我们调用同一个 id 的 Bean 会是在内容地址相同的实例,当然在 Spring 配置文件中也可以配置非 Singleton。
销毁
destroy:当 Bean 不再需要时,会经过清理阶段,如果 Bean 实现了 DisposableBean 这个接口,会调用其实现的 destroy() 方法;
bean 标签有两个重要的属性(init-method 和 destroy-method),可以来自定义初始化和注销方法,其对应的注解分别是 @PostConstruct 和 @PreDestroy。
Spring Bean 作用域
Spring 中为 Bean 定义了 5 种作用域,分别为 singleton(单例)、prototype(原型)、request(请求)、session(会话) 和 global session(全局会话),5 种作用域说明如下:
singleton (单例模式)
Spring IOC 容器中只会存在一个共享的 Bean 实例,无论有多少个 Bean 引用它,始终指向同一对象。Singleton 作用域是 Spring 中的缺省作用域,也可以显示的将 Bean 定义为 singleton 模式,配置为:
该模式在多线程下是不安全的。
prototype(原型模式)
每次通过 Spring 容器获取 prototype 定义的 bean 时,容器都将创建一个新的 Bean 实例,每个 Bean 实例都有自己的属性和状态,而 singleton 全局只有一个对象。
一般而言,对有状态的 Bean 使用 prototype 作用域,而对无状态的 Bean 使用 singleton 作用域。
request(单次请求模式)
在一次 Http 请求中,容器会返回该 Bean 的同一实例。而对不同的 Http 请求则会产生新的 Bean,而且该 Bean 仅在当前 Http Request 内有效,当前 Http 请求结束,该 bean实例也将会被销毁。
session(会话模式)
在一次 Http Session 中,容器会返回该 Bean 的同一实例。而对不同的 Session 请求则会创建新的实例,该 Bean 实例仅在当前 Session 内有效。同 Http 请求相同,每一次 Session 请求创建新的实例,而不同的实例之间不共享属性,且实例仅在自己的 Session 请求内有效,请求结束,则实例将被销毁。
global Session(全局会话模式)
global Session:在一个全局的 Http Session 中,容器会返回该 Bean 的同一个实例,仅在使用 portlet context 时有效。