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