
3.4 Bean的作用域和生命周期
在3.1.2节容器启动获得BeanDefinition对象中有一个scope属性。该属性控制着bean对象的作用域。本节介绍Bean的作用域及生命周期,了解bean是怎么来的、怎么没的。
3.4.1 Bean的作用域
在3.1.2节中介绍到Bean容器启动会先读取bean的xml配置文件,然后将xml中每个bean元素分别转换成BeanDefinition对象。在BeanDefinition对象中有scope属性,就是它控制着bean的作用域。
Spring框架支持5种作用域,有3种作用域是当开发者使用基于Web的ApplicationContext时才生效的。表3-2给出了Spring直接支持的作用域。当然开发者也可以自己定制作用域。
表3-2 Spring直接支持的作用域

我们可以以XMLInstance类为基础演示一下singleton和prototype作用域。
这里使用通过BeanFactory的getBean方法获取两次bean对象。
XMLInstance instance=(XMLInstance)factory.getBean("xmlinstance"); instance.setName("123"); instance.Breath(); instance=(XMLInstance)factory.getBean("xmlinstance"); instance.Breath();
如果我们采用bean默认的作用域singleton,如下配置,那么两个getBean获取的对象是一致的。
<bean id="xmlinstance" class="com.demo.model.XMLInstance" scope="singleton"> <property name="air" ref="CleanAir"></property> <property name="name" value="abc"></property> </bean>
输出结果:
Name:123;Air:CleanAir Name:123;Air:CleanAir
如果我们采用bean默认的作用域prototype,如下配置,那么两个getBean获取的对象是不一致的。
<bean id="xmlinstance" class="com.demo.model.XMLInstance" scope="prototype"> <property name="air" ref="CleanAir"></property> <property name="name" value="abc"></property> </bean>
输出结果:
Name:123;Air:CleanAir Name:abc;Air:CleanAir
3.4.2 Bean的生命周期
前面章节介绍了bean容器以及bean的配置与注入,本节学习bean的生命周期(见图3-1),了解bean是怎么来的、怎么没的。

图3-1
在ApplicationContext容器中,Bean的生命周期流程如图3-1所示。
(1)容器启动后,会对scope为singleton且非懒加载的bean进行实例化。
(2)按照Bean定义信息配置信息,注入所有的属性。
(3)如果Bean实现了BeanNameAware接口,会回调该接口的setBeanName()方法,传入该Bean的id,此时该Bean就获得了自己在配置文件中的id。
(4)如果Bean实现了BeanFactoryAware接口,会回调该接口的setBeanFactory()方法,传入该Bean的BeanFactory,这样该Bean就获得了自己所在的BeanFactory。
(5)如果Bean实现了ApplicationContextAware接口,会回调该接口的setApplicationContext()方法,传入该Bean的ApplicationContext,这样该Bean就获得了自己所在的ApplicationContext。
(6)如果有Bean实现了BeanPostProcessor接口,就会回调该接口的postProcessBefore-Initialzation()方法。
(7)如果Bean实现了InitializingBean接口,就会回调该接口的afterPropertiesSet()方法。
(8)如果Bean配置了init-method方法,就会执行init-method配置的方法。
(9)如果Bean实现了BeanPostProcessor接口,就会回调该接口的postProcessAfterInitialization()方法。
(10)之后,就可以正式使用该Bean了。对于scope为singleton的Bean,Spring的ioc容器中会缓存一份该Bean的实例;对于scope为prototype的Bean,每次被调用都会新建一个新的对象,其生命周期就交给调用方管理了,不再是由Spring容器进行管理了。
(11)容器关闭后,如果Bean实现了DisposableBean接口,就会回调该接口的destroy()方法。
(12)如果Bean配置了destroy-method方法,就会执行destroy-method配置的方法。至此,整个Bean的生命周期结束。
这里在UserBean类基础上进行改造,增加name属性并实现ApplicationContextAware接口。


定义后置处理器CusBeanPostProcessor,实现BeanPostProcessor接口。

在xml中配置bean和BeanPostProcessor。

测试:
ApplicationContext context=new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"}); BeanFactory factory=context; UserBean user=(UserBean)context.getBean("user"); ((ClassPathXmlApplicationContext)context).close();
输出结果如图3-2所示。

图3-2