你的位置:首页 > Java教程

[Java教程]Spring容器中Bean的生命周期


日出日落,春去秋来,花随流水,北雁南飞,世间万物皆有生死轮回。从调用

 

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

 

 

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

1-2:创建实例;

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

3-4:注入依赖关系;

  第3步是创建实例之后处理了一些事情,第4步是把

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 <??> 2 <beans ="http://www.springframework.org/schema/beans" 3   ="http://www.w3.org/2001/ ="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.

在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. 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.);  18    BeanFactory bf = new 19   20    /**BeanFactory是ConfigurableBeanFactory的父类,且该父类没有这个添加方法,所以要转换。*/21    ((ConfigurableBeanFactory)bf).addBeanPostProcessor(new MyInstantiationAwareBeanPostProcessor()); 22    //BeanPostProcessor23    ((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     ((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] (

  行1:加载

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

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

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

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

  行6:注入

  行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] (

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

 

 ApplicationContext中Bean的生命周期与BeanFactory类似,但是又有不同。对于InstantiationAwareBeanPostProcessor和MyBeanPostProcessor,BeanFactory需要在代码中注册方才能使用,而ApplicationContext只需要在

 

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