`
fanjf
  • 浏览: 295570 次
  • 性别: Icon_minigender_1
  • 来自: 安徽
社区版块
存档分类
最新评论

也谈Spring Bean的生命周期

阅读更多

开篇先用一张老图描述下 Spring Bean 容器的生命周期。

 

插叙一下,记得某个博文中提到:“ Spring Bean 容器只管理非单例 Bean 的生命周期,单例 Bean 的生命周期不在管理范围内”,其实我认为这句话恰好说反了。首先明确一点,并非 Spring 容器中所有的 Bean 都有生命周期行为,只有接受容器管理生命周期的 Bean 才具有生命周期行为:而单例( Singleton Bean 接受容器管理,非单例( non-singleton Bean 在实例化后,完全交给了客户端代码管理,容器不再跟踪其生命周期,每次客户请求,容器都会创建一个新的实例,所以 Spring 容易无法知晓 Bean 何时销毁。

 

继续刚才的话题—— Bean 容器的生命周期。其实上图有个节点没有画出,就是在实例化所有 Bean 之前会执行 BeanFactoryPostProcessors 。不过也不 care ,因为这和 Bean 的生命周期没有太大关系,所以没有提及也属正常,权且忽略该节点。

从图中,我们可以看到实例化 Bean 的过程中有以下几个节点:

1)设置属性值;

2)调用 Bean 中的 BeanNameAware.setBeanName() 方法,如果该 Bean 实现了 BeanNameAware 接口;

3)调用 Bean 中的 BeanFactoryAware.setBeanFactory() 方法,如果该 Bean 实现了 BeanFactoryAware 接口;

4)调用 BeanPostProcessors. postProcessBeforeInitialization () 方法;

5)调用 Bean 中的 afterPropertiesSet 方法,如果该 Bean 实现了 InitializingBean 接口;

6)调用 Bean 中的 init-method ,通常是在配置 bean 的时候指定了 init-method ,例如: <bean class="beanClass" init-method="init" ></bean>

7)调用 BeanPostProcessors. postProcess After Initialization () 方法;

8)如果该 Bean 是单例的,则当容器销毁并且该 Bean 实现了 DisposableBean 接口的时候,调用 destory 方法;如果该 Bean prototype ,则将准备好的 Bean 提交给调用者,后续不再管理该 Bean 的生命周期。

 

好了,简单了描述了下那幅图。一切都还太抽象了,作为程序员,代码还是最直接的表达方式。那我们就一起看段演示代码吧。

 

首先,为达到演示效果,我们准备两个待测试的 Bean ,代码如下:

Java代码  
  1. @Component   
  2. public   class  DemoBean  implements  BeanFactoryAware, BeanNameAware,  
  3.         InitializingBean, DisposableBean {  
  4.      @PostConstruct   
  5.      public   void  init() {  
  6.        System.out.println( "DemoBean: init-method" );  
  7.     }  
  8.      public   void  destroy()  throws  Exception {  
  9.        System.out.println( "DemoBean: destroy-method!" );  
  10.     }  
  11.      public   void  afterPropertiesSet()  throws  Exception {  
  12.        System.out.println( "DemoBean: after properties set!" );  
  13.     }  
  14.      public   void  setBeanName(String name) {  
  15.        System.out.println( "DemoBean: beanName aware, [name="  + name +  "]" );  
  16.     }  
  17.      public   void  setBeanFactory(BeanFactory beanFactory)  throws  BeansException {  
  18.        System.out.println( "DemoBean: beanFactory aware, [beanFactory="  + beanFactory.toString() +  "]" );  
  19.     }  
  20. }  

  

 

Java代码  
  1. public   class  AnotherDemoBean  implements  InitializingBean {  
  2.    
  3.      @PostConstruct   
  4.      public   void  postConstruct() {  
  5.        System.out.println( "AnotherDemoBean: postConstruct-method" );  
  6.     }    
  7.      public   void  init() {  
  8.        System.out.println( "AnotherDemoBean: init-method" );  
  9.     }  
  10.      @Override   
  11.      public   void  afterPropertiesSet()  throws  Exception {  
  12.        System.out.println( "AnotherDemoBean: after properties set!" );  
  13.     }  
  14. }  
 

上面两个 Bean 大致相同,区别在于第一个 Bean 使用注解方式注入,第二个 Bean 我们使用配置文件方式,并指定其 init-method ,用于观察 init-method postConstruct 的执行先后。

 

我们这个演示 Bean 实现了 BeanFactoryAware, BeanNameAware, InitializingBean,   DisposableBean 这几个接口,其实这些接口也可理解为 Spring 容器的一个个扩展点。

 

然后,我们再编写一个 BeanPostProcessor ,用于演示生命周期中的步骤 4 和步骤 7   代码如下:

Java代码  
  1. @Component   
  2. public   class  DemoBeanPostProcessor  implements  BeanPostProcessor {  
  3.      public  Object postProcessBeforeInitialization(Object bean, String beanName)  throws  BeansException {  
  4.        System.out.println( "DemoBeanPostProcessor: post process before initialization, [beanName="  + beanName +  ", bean="  + bean +  "]" );  
  5.         return  bean;  
  6.     }  
  7.      public  Object postProcessAfterInitialization(Object bean, String beanName)  throws  BeansException {  
  8.        System.out.println( "DemoBeanPostProcessor: post process before initialization, [beanName="  + beanName +  ", bean="  + bean +  "]" );  
  9.         return  bean;  
  10.     }  
  11. }  

  

最后,我们编写测试类,以及 Spring 的配置文件,这里我们使用 ClassPathXMLApplicationContext 加载配置文件和初始化 Spring 容器。一起看下配置文件和测试类代码:

applicationContext.xml:

Xml代码  
  1. <? xml   version = "1.0"   encoding = "GBK" ?>   
  2.    
  3. < beans   xmlns = "http://www.springframework.org/schema/beans"   
  4.      xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"   xmlns:aop = "http://www.springframework.org/schema/aop"   
  5.      xmlns:context = "http://www.springframework.org/schema/context"   xmlns:tx = "http://www.springframework.org/schema/tx"   
  6.      xsi:schemaLocation ="  
  7.         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
  8.         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd  
  9.         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd  
  10.         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" >   
  11.      < context:component-scan   base-package = "com.shansun.multidemo" > </ context:component-scan >   
  12.      < bean   class = "com.shansun.multidemo.spring.lifecycle.AnotherDemoBean"   init-method = "init" > </ bean >   
  13. </ beans >   

  

Main.java

Java代码  
  1. public   class  Main {  
  2.      @SuppressWarnings ( "unused" )  
  3.      public   static   void  main(String[] args) {  
  4.         ApplicationContext ctx =  new  ClassPathXmlApplicationContext( "applicationContext.xml" );  
  5.     }  
  6. }  

  

好了,一切就绪,我们就静观程序输出吧:

Java代码  
  1. DemoBean: beanName aware, [name=demoBean]  
  2. DemoBean: beanFactory aware, [beanFactory=org.springframework.beans.factory.support.DefaultListableBeanFactory @888e6c :defining beans [demoBean,demoBeanFactoryPostProcessor,demoBeanPostProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,com.shansun.multidemo.spring.lifecycle.AnotherDemoBean# 0 ]; root of factory hierarchy]  
  3. DemoBean: init-method  
  4. DemoBeanPostProcessor: post process before initialization, [beanName=demoBean, bean=com.shansun.multidemo.spring.lifecycle.DemoBean @1deeb40 ]  
  5. DemoBean: after properties set!  
  6. DemoBeanPostProcessor: post process before initialization, [beanName=demoBean, bean=com.shansun.multidemo.spring.lifecycle.DemoBean @1deeb40 ]  
  7. AnotherDemoBean: postConstruct-method  
  8. DemoBeanPostProcessor: post process before initialization, [beanName=com.shansun.multidemo.spring.lifecycle.AnotherDemoBean# 0 , bean=com.shansun.multidemo.spring.lifecycle.AnotherDemoBean @1a7ddcf ]  
  9. AnotherDemoBean: after properties set!  
  10. AnotherDemoBean: init-method  
  11. DemoBeanPostProcessor: post process before initialization, [beanName=com.shansun.multidemo.spring.lifecycle.AnotherDemoBean# 0 , bean=com.shansun.multidemo.spring.lifecycle.AnotherDemoBean @1a7ddcf ]  

  

和我们预期的是否一样呢?是的。观察结果发现一个有趣的地方:在配置文件中指定的 init-method 和使用 @PostConstruct 注解的方法,孰先孰后呢,两者是否等同呢? 后续我将通过分析源码给出结论

 

我们通过演示代码也验证了 Bean 容器的生命周期,但是还缺点什么吧。对了,透过 Spring 源码讲述 Bean 容器的生命周期是否更加直观和令人信服呢?下面我们去 Spring 源码中一探究竟。这里我们选用的是 spring-2.5.6.SEC02

 

大家应该都知道 Spring BeanFactory ApplicationContext 的关系了吧, ApplicationContext 继承自 BeanFactory ,所以可以操作到 bean 。更详细的内容可以参考许令波同学的《 Spring 框架的设计理念与设计模式分析》,里面有较清晰的分析。

 

好了,闲话不多说。

 

首先,我们探视下实例化 Bean 的方法 initializeBean ,该方法在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory 类下,一起看下该段代码:

Java代码  
  1. protected  Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {  
  2.           if  (bean  instanceof  BeanNameAware) {  
  3.                    ((BeanNameAware) bean).setBeanName(beanName);  
  4.          }  
  5.    
  6.           if  (bean  instanceof  BeanClassLoaderAware) {  
  7.                    ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());  
  8.          }  
  9.    
  10.           if  (bean  instanceof  BeanFactoryAware) {  
  11.                    ((BeanFactoryAware) bean).setBeanFactory( this );  
  12.          }  
  13.    
  14.          Object wrappedBean = bean;  
  15.           if  (mbd ==  null  || !mbd.isSynthetic()) {  
  16.                    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);  
  17.          }  
  18.    
  19.           try  {  
  20.                    invokeInitMethods(beanName, wrappedBean, mbd);  
  21.          }  
  22.           catch  (Throwable ex) {  
  23.                     throw   new  BeanCreationException(  
  24.                                      (mbd !=  null  ? mbd.getResourceDescription() :  null ),  
  25.                                      beanName,  "Invocation of init method failed" , ex);  
  26.          }  
  27.    
  28.           if  (mbd ==  null  || !mbd.isSynthetic()) {  
  29.                    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);  
  30.          }  
  31.           return  wrappedBean;  
  32. }  

  

这样够直观了吧,是不是和前文描述的一样呢, J

 

本文源代码下载: https://lb-multi-demo.googlecode.com/svn/trunk/spring-lifecycle-test

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics