五、Bean的作用域和生命周期
5.1 Bean的作用域
Spring为Bean的实例定义了7中作用域:
作用域名称 | 说明 |
---|---|
singleton(单例) | 使用singleton定义的Bean在Spring容器中将只有一个实例,也就是说,无论有多少个Bean引用它,始终将指向同一个对象。这也是Spring容器默认的作用域 |
prototype(原型) | 每次通过Spring容器获取的prototype定义的Bean时,容器都将创建一个新的Bean实例 |
request | 在一次HTTP请求中,容器会返回该Bean的同一个实例。对不同的HTTP请求则会产生一个新的Bean,而且该Bean仅在当前HTTP Request内有效 |
session | 在一次HTTP Session中,容器会返回该Bean的同一个实例。对不同的HTTP请求则会产生一个新的Bean,而且该Bean仅在当前HTTP Session内有效 |
globalSession | 在一个全局的HTTP Session中,容器会返回该Bean的同一个实例。仅在使用portlet上下文时有效 |
application | 为每个ServletContext对象创建一个实例。仅在Web相关的ApplicationContext中生效 |
websocket | 为每个websocket对象创建一个实例。仅在Web相关的ApplicationContext中生效 |
这7种作用域中,singleton和prototype是最常用的两种。
-
singleton作用域
singleton是Spring容器默认的作用域,当Bean的作用域为singleton时,Spring容器就只会存在一个共享的Bean实例,并且所有对Bean的请求,只要id与该Bean的id属性相匹配,就会返回同一个Bean实例。singleton作用域对于无会话状态的Bean(如Dao组件、Service组件)来说,是最理想的选择。在Spring配置文件中,Bean的作用域是通过bean元素的scope属性来指定的:
<!--该作用域下只返回一个Bean实例--> <bean id="scope" class="cn.spring.scope" scope="singleton" />
需要注意的是:
如果不设置scope=“singleton”,其输出结果也是一个实例,因为Spring容器默认的作用域就是singleton。 -
prototype作用域
对需要保持会话状态的Bean应该使用prototype作用域。在使用prototype作用域时,Spring容器会对每个对该Bean的请求都创建一个新的实例。在Spring配置文件中,Bean的作用域时通过bean元素的scope属性来指定的:
<!--该作用域下会对每个该Bean的请求都创建一个新的实例--> <bean id="scope" class="cn.spring.scope" scope="prototype" />
5.2 Bean的生命周期
在Spring中,Bean生命周期的执行是一个很复杂的过程,我们可以利用Spring提供的方法来定制Bean的创建过程。当一个Bean被加载到Spring容器时,它就具有了生命,而Spring容器在保证一个Bean能够使用之前,会做很多的工作:
- Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化
- Bean实例化后对将Bean的引入和值注入到Bean的属性中
- 如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法
- 如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
- 如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。
- 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。
- 如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
- 如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。
- 此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。
- 如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。
小贴士:
Spring为Bean提供了细致全面的生命周期过程,通过实现特点的接口或通过bean的属性设置,都可以对Bean的生命周期过程产生影响。我们可以随意地配置bean的属性,但是这里建议不要过多地使用Bean实现接口,因为这样会使代码和Spring聚合比较紧密。