开篇先用一张老图描述下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.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]
DemoBean: init-method
DemoBeanPostProcessor: post process before initialization, [beanName=demoBean, bean=com.shansun.multidemo.spring.lifecycle.DemoBean@1deeb40]
DemoBean: after properties set!
DemoBeanPostProcessor: post process before initialization, [beanName=demoBean, bean=com.shansun.multidemo.spring.lifecycle.DemoBean@1deeb40]
AnotherDemoBean: postConstruct-method
DemoBeanPostProcessor: post process before initialization, [beanName=com.shansun.multidemo.spring.lifecycle.AnotherDemoBean#0, bean=com.shansun.multidemo.spring.lifecycle.AnotherDemoBean@1a7ddcf]
AnotherDemoBean: after properties set!
AnotherDemoBean: init-method
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类下,一起看下该段代码:
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
分享到:
相关推荐
spring bean 的生命周期,把运行结果的日志,用sublime打开对比查看,你会有比较清晰的认识
Spring bean生命周期demo
Springbean生命周期
SpringBean的生命周期.mdj
此资源是我的博客bean的生命周期的测试代码,只有源代码,没有相关库文件,环境是spring4.2 ,
Spring Bean 的生命周期在整个 Spring 中占有很重要的位置,掌握这些可以加深对 Spring 的理解。这篇文章主要介绍了Spring Bean 生命周期,需要的朋友可以参考下
本篇文章主要介绍了浅谈Spring bean 生命周期验证,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
Spring Bean 生命周期之“我从哪里来?”
这个工程主要实现了: Spring中Bean的生命周期 applicationcontext的应用(实现国际化,事件的传递)
介绍了Spring的Bean周期,容器周期,工厂周期,运行代码后可以看到运行结果
四份资料介绍Spring Bean 的生命周期,从认识,熟悉,深究,记忆Spring Bean。希望这份资料能帮助你!
虽然可以随意配置 <bean> 的属性,但是建议不要过多地使 Bean 实现接,因为这样会导致代码和 Spring 的聚合过于紧密第 1 步:实例化Bean第
主要给大家介绍了Spring中Bean的生命周期和作用域及实现方式的相关资料,文中介绍的非常详细,对大家具有一定的参考价值,需要的朋友们下面来一起看看吧。
Spring的生命周期是指实例化Bean时所经历的一系列阶段,即通过getBean()获取bean对象及设置对象属性时,Spring框架做了哪些事。Bean的生命周期从Spring容器实例化Bean到销毁Bean。 本文分别对 BeanFactory 和 ...
主要介绍了Spring Bean的生命周期的相关资料,需要的朋友可以参考下
学习Spring过程中,使用Eclipse调试Spring源码的关键断点文件。
Spring管理的Bean的生命周期
一般情况下,我们只是关心如何正确地将Bean装配到容器中,并不关心Ioc容器是如何装配和销毁Bean的过程。但是恰恰有时候,我们需要自定义初始化或销毁Bean的过程,以满足一些“特殊的”需求。比如,数据源在关闭的...
主要介绍了Spring bean生命周期配置过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
SPRING BOOT介绍点击lastest release就可进入到下载页,然后下载对应的版本从disk安装即可。点击lastest release就可进入到下载页,然后下载对应的版本从disk安装即可。点击lastest release就可进入到下载页,然后...