Spring Bean 生命周期

转自:也谈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.postProcessAfterInitialization()方法;

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

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

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

@Component
public class DemoBean implements BeanFactoryAware, BeanNameAware,
        InitializingBean, DisposableBean {
    @PostConstruct
    public void init() {
       System.out.println("DemoBean: init-method");
    }
    public void destroy() throws Exception {
       System.out.println("DemoBean: destroy-method!");
    }
    public void afterPropertiesSet() throws Exception {
       System.out.println("DemoBean: after properties set!");
    }
    public void setBeanName(String name) {
       System.out.println("DemoBean: beanName aware, [name=" + name + "]");
    }
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
       System.out.println("DemoBean: beanFactory aware, [beanFactory=" + beanFactory.toString() + "]");
    }
}  
public class AnotherDemoBean implements InitializingBean {  

    @PostConstruct
    public void postConstruct() {
       System.out.println("AnotherDemoBean: postConstruct-method");
    }
    public void init() {
       System.out.println("AnotherDemoBean: init-method");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
       System.out.println("AnotherDemoBean: after properties set!");
    }
}  

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

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

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

@Component
public class DemoBeanPostProcessor implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
       System.out.println("DemoBeanPostProcessor: post process before initialization, [beanName=" + beanName + ", bean=" + bean + "]");
       return bean;
    }
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
       System.out.println("DemoBeanPostProcessor: post process before initialization, [beanName=" + beanName + ", bean=" + bean + "]");
       return bean;
    }
}  

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

applicationContext.xml:

<?xml version="1.0" encoding="GBK"?>  

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
    <context:component-scan base-package="com.shansun.multidemo"></context:component-scan>
    <bean class="com.shansun.multidemo.spring.lifecycle.AnotherDemoBean" init-method="init"></bean>
</beans>  

Main.java

public class Main {
    @SuppressWarnings("unused")
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    }
}  

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

DemoBean: beanName aware, [name=demoBean]
DemoBean: beanFactory aware, [beanFactory=org.s[email protected]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]
DemoBean: init-method
DemoBeanPostProcessor: post process before initialization, [beanName=demoBean, bean=[email protected]]
DemoBean: after properties set!
DemoBeanPostProcessor: post process before initialization, [beanName=demoBean, bean=[email protected]]
AnotherDemoBean: postConstruct-method
DemoBeanPostProcessor: post process before initialization, [beanName=com.shansun.multidemo.spring.lifecycle.AnotherDemoBean#0, bean=[email protected]]
AnotherDemoBean: after properties set!
AnotherDemoBean: init-method
DemoBeanPostProcessor: post process before initialization, [beanName=com.shansun.multidemo.spring.lifecycle.AnotherDemoBean#0, [email protected]dcf] 

和我们预期的是否一样呢?是的。观察结果发现一个有趣的地方:在配置文件中指定的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类下,一起看下该段代码:

protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
         if (bean instanceof BeanNameAware) {
                   ((BeanNameAware) bean).setBeanName(beanName);
         }  

         if (bean instanceof BeanClassLoaderAware) {
                   ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
         }  

         if (bean instanceof BeanFactoryAware) {
                   ((BeanFactoryAware) bean).setBeanFactory(this);
         }  

         Object wrappedBean = bean;
         if (mbd == null || !mbd.isSynthetic()) {
                   wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
         }  

         try {
                   invokeInitMethods(beanName, wrappedBean, mbd);
         }
         catch (Throwable ex) {
                   throw new BeanCreationException(
                                     (mbd != null ? mbd.getResourceDescription() : null),
                                     beanName, "Invocation of init method failed", ex);
         }  

         if (mbd == null || !mbd.isSynthetic()) {
                   wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
         }
         return wrappedBean;
}  

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

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

By Mr.Chris

时间: 2024-08-01 22:25:33

Spring Bean 生命周期的相关文章

Spring点滴四:Spring Bean生命周期

Spring Bean 生命周期示意图: 了解Spring的生命周期非常重要,我们可以利用Spring机制来定制Bean的实例化过程. --------------------------------------------------------------------------------------------------------------------------------------------------- spring-service.xml: <?xml version=

一步步剖析spring bean生命周期

关于spring bean的生命周期,是深入学习spring的基础,也是难点,本篇文章将采用代码+图文结论的方式来阐述spring bean的生命周期, 本篇文章将阐述清楚下图. 一  项目结构及源码 1.程序目录结构 2.applicationContext.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/sc

Spring Bean生命周期

1.Bean的建立:BeanFactory容器寻找Bean的定义信息,读取Bean定义文件,并将其实例化,生成各个Bean实例.2.属性注入:使用依赖注入,Spring按照Bean定义信息配置Bean所有属性.3.BeanNameAware的setBeanName():传递Bean的ID.4.BeanFactoryAware的setBeanFactory():工厂调用setBeanFactory()方法传入工厂自身.如果是使用ApplicationContext来生成并管理Bean的话则稍有不同

Spring Bean生命周期详解

对象生命周期:创建(实例化----初始化)---使用----销毁,而在Spring中,Bean对象周期当然遵从这一过程,但是Spring提供了许多对外接口,允许开发者对三个过程(实例化.初始化.销毁)的前后做一些操作.在Spring Bean中,实例化是为Bean对象开辟空间(构造函数),初始化则是对属性的初始化,属性注入(setter方法注入属性). 1.Bean自身方法:init-method/destroy-method,通过为配置文件bean定义中添加相应属性指定相应执行方法. 2.Be

11张流程图帮你搞定 Spring Bean 生命周期

在网上已经有跟多Bean的生命周期的博客,但是很多都是基于比较老的版本了,最近吧整个流程化成了一个流程图.待会儿使用流程图,说明以及代码的形式来说明整个声明周期的流程.注意因为代码比较多,这里的流程图只画出了大概的流程,具体的可以深入代码 一.获取Bea 第一阶段获取Bean 这里的流程图的入口在 AbstractBeanFactory类的 doGetBean方法,这里可以配合前面的 getBean方法分析文章进行阅读.主要流程就是 1.先处理Bean 的名称,因为如果以“&”开头的Bean名称

Spring Bean生命周期回调方法

参阅官方文档:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-lifecycle 第一种方式:使用@PostConstruct注解,进行标注当前非init()名称的方法,进行bean声明周期的初始化操作:@PostConstruct和@PreDestroy是当前Bean声明周期的初始化回调和销毁时回调 第二种方式:当前类实现InitializingBean和

Spring Bean生命周期回调

参阅官方文档:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-lifecycle 第一种方式:使用@PostConstruct注解,进行标注当前非init()名称的方法,进行bean声明周期的初始化操作:@PostConstruct和@PreDestroy是当前Bean声明周期的初始化回调和销毁时回调 第二种方式:当前类实现InitializingBean和

spring bean生命周期和上下文初始化

第一阶段: 1 准备阶段根据BeanDefintionReader去初始化Bean的定义,那么在bean的定义中通常有两种一个是注解Bean定义读取器,一个是xmlBean定义读取器. BeanDefinition是spring中Bean的元数据定义: 包括:(1)bean的Scope:(2)是否懒加载:(3)simpleName:(4)parentName,(5)DependsOn 在doCreateBean中的4个方法 1 createBeanInstance2 populateBean3

spring bean 生命周期事件

整体流程图 程序示例 maven依赖 <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <vers