Spring容器中Bean的生命周期

日出日落,春去秋来,花随流水,北雁南飞,世间万物皆有生死轮回。从调用XML中的Bean配置信息,到应用到具体实例中,再到销毁,Bean也有属于它的生命周期。

人类大脑对图像的认知能力永远高于文字,因此,闲言少叙,书归正传,上图先:

步骤很多,切莫惊慌,我们可以把上面的步骤归纳如下:

1-2:创建实例;

  现在假设spring就是个容器,而配置文件中配置的bean属性才是我们真正需要的东西。创建实例就是说,我把配置文件中的bean信息取出来化作一个真正的bean并放到容器中。

3-4:注入依赖关系;

  第3步是创建实例之后处理了一些事情,第4步是把xml中配置的bean属性值赋予给容器中的实例化之后的bean。

5:bean初始化之前的处理;

  应用开发者需要把容器中实例化的bean拿出来用,这个拿出来的过程就是初始化(注意实例化与初始化的区别,instantiation 和initialization,分得清吗?英语没学好怪我咯?),第五步就是在初始化之前,对已经实例化的bean再作一定的处理。

6,7:初始化。

  如果bean实现了InitializingBean,那么将调用InitializingBean的afterPropertiesSet()方法做一些初始化处理。如果没有实现InitializingBean,而是在配置文件中定义了init-method属性值,那么系统会找到init-method对应的方法并执行之,程序猿哥哥一般在这个方法里写一些初始化操作;

8:bean初始化之后的处理。

  初始化之后在这个方法中再对bean进行修饰装点。

9,10:交给应用开发人员处理;

  如果在<bean>中指定Bean的作用范围是scopt="prototype",那么系统将bean返回给调用者,spring就不管了(如果两个实例调用的话,每一次调用都要重新初始化,一个实例的修改不会影响另一个实例的值。如果指定Bean的作用范围是scope="singleton",则把bean放到缓冲池中,并将bean的引用返回给调用者。这个时候,如果两个实例调用的话,因为它们用的是同一个引用,任何一方的修改都会影响到另一方。)

11.bean用完之后;

  对于scope="singleton"的bean,使用完之后spring容器会做一些处理,比如编写释放资源、记录日志等操作。

12.销毁;

  调用配置文件中的销毁方法销毁实例。

光说不练假把式。来看实例:

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
 4     xsi:schemaLocation="http://www.springframework.org/schema/beans
 5        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 6     <bean id="jay" class="com.mesopotamia.bean_life_cycle.JayChou"
 7          init-method="myInit"
 8          destroy-method="myDestory"
 9          p:sex="男"
10          p:girlFriend="蔡依林"
11          p:profession="歌手,演员,导演,主持"
12          scope="singleton"
13          />
14 </beans>

上面是配置文件,取名为jayConfig.xml,注意bean中定义了init-method、destroy-method属性,翻阅上文查看这两个属性的作用。该bean还定义了scope属性,对应第9步。

在BeanFactory的bean生命周期中,第1、3、5、8步是由程序员自己扩展的。自己扩展类并在代码中注册使用。具体如下:

 1 package com.mesopotamia.bean_life_cycle;
 2
 3 import java.beans.PropertyDescriptor;
 4
 5 import org.springframework.beans.BeansException;
 6 import org.springframework.beans.PropertyValues;
 7 import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
 8
 9 public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter{
10
11     public Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException {
12         if("jay".equals(beanName)){
13             System.out.println("MyInstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation");
14         }
15         return null;
16     }
17     /**实例化Bean后,对Bean进行梳妆打扮*/
18     public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
19         if("jay".equals(beanName)){
20         System.out.println("InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation");
21         }
22         return true;
23     }
24
25     //把Bean的配置值赋值给Bean实例的属性。
26     public PropertyValues postProcessPropertyValues(
27             PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
28             throws BeansException {
29         if("jay".equals(beanName)){
30            System.out.println("InstantiationAwareBeanPostProcessor.postProcessPropertyValues");
31         }
32         return pvs;
33     }
34
35     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
36         return bean;
37     }
38
39     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
40         return bean;
41     }
42 }

上面的类是继承了InstantiationAwareBeanPostProcessorAdopter的,而InstantiationAwareBeanPostProcessorAdopter这个适配器与是InstantiationAwareBeanPostProcessor的扩展类。

 1 package com.mesopotamia.bean_life_cycle;
 2
 3 import org.apache.commons.logging.Log;
 4 import org.apache.commons.logging.LogFactory;
 5 import org.springframework.beans.BeansException;
 6 import org.springframework.beans.factory.config.BeanPostProcessor;
 7
 8
 9 public class MyBeanPostProcessor implements BeanPostProcessor{
10
11     private Log log=LogFactory.getLog(MyBeanPostProcessor.class);
12
13     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
14         if(beanName.equals("jay")){
15             JayChou jay = (JayChou)bean;
16             log.info("JayChou当前的女朋友是:"+jay.getGirlFriend());
17             jay.setGirlFriend("昆凌");
18             log.info("调用BeanPostProcessor的postProcessAfterInitialization处理后," +
19                     "JayChou的女朋友变成:"+jay.getGirlFriend());
20         }
21         return bean;
22
23     }
24
25     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
26         if(beanName.equals("jay")){
27             JayChou jay = (JayChou)bean;
28             log.info("配置文件中Jay的女朋友是:"+jay.getGirlFriend());
29             jay.setGirlFriend("侯佩岑");
30             log.info("调用BeanPostProcessor的postProcessBeforeInitialization处理后," +
31                     "Jay的女朋友变为:"+jay.getGirlFriend());
32
33         }
34         return bean;
35     }
36 }

上面的代码实现了BeanPostProcessor。InstantiationAwareBeanPostProcessor是实例化前后做的事情,BeanPostProcessor是初始化前后做的事情,它们之间应该存在着父子关系吧?当然是,从名字就能看出来前者是后者的扩展类,读者可以自己下载spring源码查看。这两个类定义好了需要注册才能使用,稍后再讲。这里先讲bean类:

 1 package com.mesopotamia.bean_life_cycle;
 2
 3 import org.apache.commons.logging.Log;
 4 import org.apache.commons.logging.LogFactory;
 5 import org.springframework.beans.factory.DisposableBean;
 6 import org.springframework.beans.factory.InitializingBean;
 7
 8 public class JayChou implements InitializingBean,DisposableBean {
 9
10     private static Log log=LogFactory.getLog(JayChou.class);
11     private String sex;
12     private String profession;
13     private String girlFriend;
14
15
16
17     public JayChou(){
18         log.info("调用JayChou的无参构造函数。杰伦出道啦。");
19     }
20
21     public String getSex() {
22         return sex;
23     }
24
25     public void setSex(String sex) {
26         this.sex = sex;
27     }
28
29
30     public void setGirlFriend(String girlFriend) {
31         this.girlFriend = girlFriend;
32     }
33
34     public String getGirlFriend() {
35         return girlFriend;
36     }
37
38     public String getProfession() {
39         return profession;
40     }
41
42     public void setProfession(String profession) {
43         this.profession = profession;
44     }
45
46
47     public void afterPropertiesSet() throws Exception {
48         this.profession="歌手";
49         log.info("调用InitializingBean.afterPropertiesSet()," +
50                 "属性配置完毕了再做些善后工作。");
51
52     }
53
54     public void destroy() throws Exception {
55         log.info("调用DisposableBean.destory(),销毁。。");
56
57     }
58
59     public void myInit() {
60         this.girlFriend = "徐若瑄";
61         log.info("通过调用配置文件初始化女朋友为:"+this.girlFriend);
62     }
63
64     public void myDestory() {
65         System.out.println("调用myDestroy()。");
66     }
67
68     public String toString(){
69         return "JayChou简介:" +
70                 "    性别:"+sex+
71                 "    职业:"+profession+
72                 "    女朋友:"+girlFriend;
73     }
74
75
76 }

这个bean实现了InitializingBean,DisposableBean,那么第六步和第11步就可以用得到了。

下面看Main方法类:

 1 package com.mesopotamia.bean_life_cycle;
 2
 3 import org.apache.commons.logging.Log;
 4 import org.apache.commons.logging.LogFactory;
 5 import org.springframework.beans.factory.BeanFactory;
 6 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 7 import org.springframework.beans.factory.xml.XmlBeanFactory;
 8 import org.springframework.core.io.ClassPathResource;
 9 import org.springframework.core.io.Resource;
10
11
12 public class BeanLifeCycleMain {
13
14     private static Log log=LogFactory.getLog(BeanLifeCycleMain.class);
15
16     private static void LifeCycleInBeanFactory(){
17         Resource res = new ClassPathResource("com/mesopotamia/bean_life_cycle/jayConfig.xml");
18        BeanFactory bf = new XmlBeanFactory(res);
19
20        /**BeanFactory是ConfigurableBeanFactory的父类,且该父类没有这个添加方法,所以要转换。*/
21        ((ConfigurableBeanFactory)bf).addBeanPostProcessor(new MyInstantiationAwareBeanPostProcessor());
22        //BeanPostProcessor
23        ((ConfigurableBeanFactory)bf).addBeanPostProcessor(new MyBeanPostProcessor());
24
25        JayChou jay = (JayChou)bf.getBean("jay");
26        log.info("jay:"+jay.toString());
27
28       // jay.setGirlFriend("温岚");
29        JayChou jay2 = bf.getBean("jay",JayChou.class);
30        jay2.setGirlFriend("温岚");
31        log.info("jay2:"+jay2.toString());
32        log.info("jay:"+jay.toString());
33
34        log.info(jay == jay2);
35        ((XmlBeanFactory)bf).destroySingletons();
36     }
37     public static void main(String[] args) {
38         LifeCycleInBeanFactory();
39     }
40 }

第17、18行是装载配置文件并启动容器(相关知识请自己脑补)。第21行和23行是注册事件,注册后才能正常使用。先看一下执行结果:

1  2015-11-07 22:01:26,907  INFO [main] (XmlBeanDefinitionReader.java:315) - Loading XML bean definitions from class path resource [com/mesopotamia/bean_life_cycle/jayConfig.xml]
2  MyInstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
3  2015-11-07 22:01:27,068  INFO [main] (JayChou.java:18) - 调用JayChou的无参构造函数。杰伦出道啦。
4  InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
5  InstantiationAwareBeanPostProcessor.postProcessPropertyValues
6  2015-11-07 22:01:27,106  INFO [main] (MyBeanPostProcessor.java:28) - 配置文件中Jay的女朋友是:蔡依林
7  2015-11-07 22:01:27,106  INFO [main] (MyBeanPostProcessor.java:30) - 调用BeanPostProcessor的postProcessBeforeInitialization处理后,Jay的女朋友变为:侯佩岑
8  2015-11-07 22:01:27,106  INFO [main] (JayChou.java:49) - 调用InitializingBean.afterPropertiesSet(),属性配置完毕了再做些善后工作。
9  2015-11-07 22:01:27,106  INFO [main] (JayChou.java:61) - 通过调用配置文件初始化女朋友为:徐若瑄
10  2015-11-07 22:01:27,106  INFO [main] (MyBeanPostProcessor.java:16) - JayChou当前的女朋友是:徐若瑄
11  2015-11-07 22:01:27,107  INFO [main] (MyBeanPostProcessor.java:18) - 调用BeanPostProcessor的postProcessAfterInitialization处理后,JayChou的女朋友变成:昆凌
12  2015-11-07 22:01:27,110  INFO [main] (BeanLifeCycleMain.java:26) - jay:JayChou简介:	性别:男	职业:歌手	女朋友:昆凌
13  2015-11-07 22:01:27,110  INFO [main] (BeanLifeCycleMain.java:31) - jay2:JayChou简介:	性别:男	职业:歌手	女朋友:温岚
14  2015-11-07 22:01:27,110  INFO [main] (BeanLifeCycleMain.java:32) - jay:JayChou简介:	性别:男	职业:歌手	女朋友:温岚
15  2015-11-07 22:01:27,110  INFO [main] (BeanLifeCycleMain.java:34) - true
16  2015-11-07 22:01:27,110  INFO [main] (DefaultSingletonBeanRegistry.java:422) - Destroying singletons in [email protected]: defining beans [jay]; root of factory hierarchy
17  2015-11-07 22:01:27,111  INFO [main] (JayChou.java:55) - 调用DisposableBean.destory(),销毁。。
18  调用myDestroy()。

  行1:加载xml。

  行2:实例化之前处理了一些事情。

  行3:duang!开始实例化,实例化当然首先要执行构造函数(这是美好世界的窗口)。

  行4:实例化之后处理了一些事情。

  行5:实例化之后注入属性值之前要调用这个函数。

  行6:注入xml的属性值,可以看到是配置中的"蔡依林"。

  行7:注入属性值后,随即又把女朋友这个属性的值改为了"侯佩岑"。

  行8:属性配置完毕了做一些善后工作。在JayChou类的第48行可以看到,我把职业改为了"歌手",所以后面显示的职业都是"歌手",而不是配置文件中的"歌手,演员,导演,主持"。

  行9:调用了配置文件中的init-method。通过<bean>的class属性找到这个类,再找到属性值对应的这个方法执行。行8和行9对应流程图表中的第六步和第七步,在此可以看到先执行第6步,后执行第七步。然而,行9是在配置文件中实现的,这正符合spring容器的宗旨,而行8的实现必须implements InitializingBean,给代码带来复杂度和污染,因此行8(也就是图表第六步)一般是不提倡的。

  行10和行11是初始化之后做的事情,首先显示当前女朋友,在行9中已经改为徐若瑄。紧接着行11又把女朋友改为了昆凌。

  行12-行15:看对应的代码就会发现,两个对象其实引用的是同一个地址,jay2修改了属性之后jay1也会跟着作改变,这就是singleton配置方式的作用。

  行16是关闭容器。

  行17和行18,一个是调用DisposableBean的销毁,一个是调用配置文件的销毁,利弊取舍与上文行9的叙述相同。

  哥哥们姐姐们,那么如果把配置文件的scope属性改为"prototype"会发生什么呢?让我们看一下打印的日志:

1  2015-11-07 22:37:29,280  INFO [main] (XmlBeanDefinitionReader.java:315) - Loading XML bean definitions from class path resource [com/mesopotamia/bean_life_cycle/jayConfig.xml]
2  MyInstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
3  2015-11-07 22:37:29,407  INFO [main] (JayChou.java:18) - 调用JayChou的无参构造函数。杰伦出道啦。
4  InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
5  InstantiationAwareBeanPostProcessor.postProcessPropertyValues
6  2015-11-07 22:37:29,444  INFO [main] (MyBeanPostProcessor.java:28) - 配置文件中Jay的女朋友是:蔡依林
7  2015-11-07 22:37:29,444  INFO [main] (MyBeanPostProcessor.java:30) - 调用BeanPostProcessor的postProcessBeforeInitialization处理后,Jay的女朋友变为:侯佩岑
8  2015-11-07 22:37:29,444  INFO [main] (JayChou.java:49) - 调用InitializingBean.afterPropertiesSet(),属性配置完毕了再做些善后工作。
9  2015-11-07 22:37:29,445  INFO [main] (JayChou.java:61) - 通过调用配置文件初始化女朋友为:徐若瑄
10  2015-11-07 22:37:29,445  INFO [main] (MyBeanPostProcessor.java:16) - JayChou当前的女朋友是:徐若瑄
11  2015-11-07 22:37:29,445  INFO [main] (MyBeanPostProcessor.java:18) - 调用BeanPostProcessor的postProcessAfterInitialization处理后,JayChou的女朋友变成:昆凌
12  2015-11-07 22:37:29,446  INFO [main] (BeanLifeCycleMain.java:26) - jay:JayChou简介:	性别:男	职业:歌手	女朋友:昆凌
13  2015-11-07 22:37:29,446  INFO [main] (JayChou.java:18) - 调用JayChou的无参构造函数。杰伦出道啦。
14  InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
15  InstantiationAwareBeanPostProcessor.postProcessPropertyValues
16  2015-11-07 22:37:29,447  INFO [main] (MyBeanPostProcessor.java:28) - 配置文件中Jay的女朋友是:蔡依林
17  2015-11-07 22:37:29,447  INFO [main] (MyBeanPostProcessor.java:30) - 调用BeanPostProcessor的postProcessBeforeInitialization处理后,Jay的女朋友变为:侯佩岑
18  2015-11-07 22:37:29,447  INFO [main] (JayChou.java:49) - 调用InitializingBean.afterPropertiesSet(),属性配置完毕了再做些善后工作。
19  2015-11-07 22:37:29,447  INFO [main] (JayChou.java:61) - 通过调用配置文件初始化女朋友为:徐若瑄
20  2015-11-07 22:37:29,448  INFO [main] (MyBeanPostProcessor.java:16) - JayChou当前的女朋友是:徐若瑄
21  2015-11-07 22:37:29,448  INFO [main] (MyBeanPostProcessor.java:18) - 调用BeanPostProcessor的postProcessAfterInitialization处理后,JayChou的女朋友变成:昆凌
22  2015-11-07 22:37:29,448  INFO [main] (BeanLifeCycleMain.java:31) - jay2:JayChou简介:	性别:男	职业:歌手	女朋友:温岚
23  2015-11-07 22:37:29,448  INFO [main] (BeanLifeCycleMain.java:32) - jay:JayChou简介:	性别:男	职业:歌手	女朋友:昆凌
24  2015-11-07 22:37:29,449  INFO [main] (BeanLifeCycleMain.java:34) - false
25  2015-11-07 22:37:29,449  INFO [main] (DefaultSingletonBeanRegistry.java:422) - Destroying singletons in [email protected]: defining beans [jay]; root of factory hierarchy

  上面的日志是见证奇迹的时刻,当创建jay2对象时,从13行到21行,又进行了一次初始化的过程,而22行到24行发现,两个对象不相同了,这就是prototype的作用。

 ApplicationContext中Bean的生命周期与BeanFactory类似,但是又有不同。对于InstantiationAwareBeanPostProcessor和MyBeanPostProcessor,BeanFactory需要在代码中注册方才能使用,而ApplicationContext只需要在xml中配置,spring会自动将它们注册到应用上下文中,这是二者最大的区别,也是为什么普遍使用ApplicationContext而非BeanFactory的原因。ApplicationContext是BeanFactory的扩展类。

  spring当前在各大企业应用中广受青睐,spring融汇的java思想也堪称经典,因此笔者后面将继续跟广大猿猿一块学习探讨spring的精髓,对于文中的错误与不足,抑或是读者有一般人不告诉他的精辟见解,还望在评论中留言,一起学习。共勉。

时间: 11-05

Spring容器中Bean的生命周期的相关文章

IOC容器中bean的生命周期

一.Bean生命周期 Spring IOC容器可以管理Bean的生命周期,允许在Bean生命周期的特定点执行定制的任务. Spring IOC容器对Bean的生命周期进行管理的过程如下: 通过构造器或工厂方法创建Bean实例 为Bean的属性设置值和对其它Bean的引用 调用Bean的初始化方法 Bean可以使用了 当容器关闭时,调用Bean的销毁方法 在 Bean 的声明里设置 init-method 和 destroy-method 属性, 为 Bean 指定初始化和销毁方法. 下面通过示例

IOC容器中Bean的生命周期方法

一Spring IOC容器可以管理Bean的生命周期,Spring允许在Bean生命周期的特定点执行定制的任务. 二.Spring IOC容器对Bean的生命周期进行管理的过程: -通过构造器或工厂方法创建Bean的实例 -为Bean的属性设置值和对其他的Bean的引用 -调用Bean的初始化方法 -Bean可以用了 -当容器关闭是吗,调用Bean的销毁方法 三.在bean的声明里设置init-method和destroy-method属性.为Bean指定初始化和销毁方法.

[原创]java WEB学习笔记101:Spring学习---Spring Bean配置:IOC容器中bean的声明周期,Bean 后置处理器

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 -----------------------------------------------------------------------------------------------------------------

《Spring揭秘》(八)---- IoC容器及Bean的生命周期

Spring的IoC容器会以某种方式加载配置信息,然后根据这些信息绑定整个系统的对象,最终组装成一个可用的基于轻量级容器的应用系统.实现以上功能,分为两个阶段:容器启动阶段和Bean实例化阶段.而且Spring的IoC容器在每个阶段都加入了相应的扩展点,以便根据具体场景的需要加入自定义的扩展逻辑. 1 容器启动阶段 首先会通过某种途径加载配置信息,大部分情况下,容器需要依赖某些工具类(BeanDefinitionReader)对加载的配置信息进行解析和分析,并将分析后的信息编组为相应的BeanD

Spring中Bean的生命周期

Spring中Bean的生命周期过程: 1.Spring对Bean进行实例化(相当于程序中的new Xx()) 2.Spring将值和Bean的引用注入进Bean对应的属性中 3如果Bean实现了BeanNameAware接口,Spring将Bean的ID传递给setBeanName()方法 (实现BeanNameAware清主要是为了通过Bean的引用来获得Bean的ID,一般业务中是很少有在Bean的ID的) 4.如果Bean实现了BeanFactoryAware接口,Spring将调用se

spring容器中bean的作用范围

spring容器中bean的作用范围范围五类,bean的作用范围不同对bean的生命周期和创建方式也会产生一定的影响. singleton  以单例形式存在,容器中仅有一个bean实例. prototype  每次从容器中调用bean时,容器都创建一个新的实例,每次调用都相当于new一个新的对象. request 每次http请求都会创建一个新的bean. 此作用域仅适用于webApplicationContext环境. session 同一个session共享同一个bean,不同的sessio

Spring中Bean的生命周期方法

Bean的生命周期方法 src\dayday\Car.java package dayday; import com.sun.org.apache.xpath.internal.SourceTree; import javax.sound.midi.Soundbank; /** * Created by I am master on 2016/11/28. */public class Car { private String name; public void setName(String n

好记性不如烂笔头86-spring3学习(7)-ApplicationContext中bean的生命周期

假设使用ApplicationContext来生成.管理Bean, 一个Bean从建立到销毁,会历经几个运行阶段. 我个人理解一般的bean的生命周期主要包含:建立,初始化,使用阶段,销毁四个核心阶段.使用ApplicationContext 和BeanFactory对bean的生命周期来看,宏观上基本同样,微观上有一些差异. 假设使用ApplicationContext来生成并管理Bean.在运行BeanfactoryAware的 setBeanFactory()阶段之后.若Bean类上有实现

spring容器中bean的初始化

当我们在spring容器中添加一个bean时,如果没有指明它的scope属性,则默认是singleton,也就是单例的. 例如先声明一个bean: public class People { private String name; private String sex; public String getName() { return name; } public void setName(String name) { this.name = name; } public String get