乐趣区

Spring-Bean的生命周期

Spring Bean 的生命周期

  Spring 作为当前 Java 最流行、最强大的轻量级框架,受到了程序员的热烈欢迎。准确的了解 Spring Bean 的生命周期是非常必要的。我们通常使用 ApplicationContext 作为 Spring 容器。这里,我们讲的也是 ApplicationContext 中 Bean 的生命周期。而实际上 BeanFactory 也是差不多的,只不过处理器需要手动注册。

一、生命周期流程图:

Spring Bean 的完整生命周期从创建 Spring 容器开始,直到最终 Spring 容器销毁 Bean,这其中包含了一系列关键点。

二、各种接口方法分类
Bean 的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:
1、Bean 自身的方法:这个包括了 Bean 本身调用的方法和通过配置文件中 <bean> 的 init-method 和 destroy-method 指定的方法
2、Bean 级生命周期接口方法:这个包括了 BeanNameAware、BeanFactoryAware、InitializingBean 和 DiposableBean 这些接口的方法
3、容器级生命周期接口方法:这个包括了 InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。
4、工厂后处理器接口方法:这个包括了 AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer 等等非常有用的工厂后处理器 接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。
三、演示

   我们用一个简单的 Spring Bean 来演示一下 Spring Bean 的生命周期。

1、首先是一个简单的 Spring Bean,调用 Bean 自身的方法和 Bean 级生命周期接口方法,为了方便演示,它实现了 BeanNameAware、BeanFactoryAware、InitializingBean 和 DiposableBean 这 4 个接口,同时有 2 个方法,对应配置文件中 <bean> 的 init-method 和 destroy-method。如下:
[Java] 纯文本查看 复制代码
?

package springBeanTest;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

/**

  • @author cqy

*/
public class Person implements BeanFactoryAware, BeanNameAware,

    InitializingBean, DisposableBean {

private String name;
private String address;
private int phone;

private BeanFactory beanFactory;
private String beanName;

public Person() {System.out.println("【构造器】调用 Person 的构造器实例化");
}

public String getName() {return name;}

public void setName(String name) {System.out.println("【注入属性】注入属性 name");
    this.name = name;
}

public String getAddress() {return address;}

public void setAddress(String address) {System.out.println("【注入属性】注入属性 address");
    this.address = address;
}

public int getPhone() {return phone;}

public void setPhone(int phone) {System.out.println("【注入属性】注入属性 phone");
    this.phone = phone;
}

@Override
public String toString() {
    return "Person [address=" + address + ", name=" + name + ", phone="
            + phone + "]";
}

// 这是 BeanFactoryAware 接口方法
@Override
public void setBeanFactory(BeanFactory arg0) throws BeansException {
    System.out
            .println("【BeanFactoryAware 接口】调用 BeanFactoryAware.setBeanFactory()");
    this.beanFactory = arg0;
}

// 这是 BeanNameAware 接口方法
@Override
public void setBeanName(String arg0) {System.out.println("【BeanNameAware 接口】调用 BeanNameAware.setBeanName()");
    this.beanName = arg0;
}

// 这是 InitializingBean 接口方法
@Override
public void afterPropertiesSet() throws Exception {
    System.out
            .println("【InitializingBean 接口】调用 InitializingBean.afterPropertiesSet()");
}

// 这是 DiposibleBean 接口方法
@Override
public void destroy() throws Exception {System.out.println("【DiposibleBean 接口】调用 DiposibleBean.destory()");
}

// 通过 <bean> 的 init-method 属性指定的初始化方法
public void myInit() {System.out.println("【init-method】调用 <bean> 的 init-method 属性指定的初始化方法");
}

// 通过 <bean> 的 destroy-method 属性指定的初始化方法
public void myDestory() {System.out.println("【destroy-method】调用 <bean> 的 destroy-method 属性指定的初始化方法");
}

}

2、接下来是演示 BeanPostProcessor 接口的方法,如下:
[Java] 纯文本查看 复制代码
?

package springBeanTest;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor implements BeanPostProcessor {

public MyBeanPostProcessor() {super();
    System.out.println("这是 BeanPostProcessor 实现类构造器!!");
    // TODO Auto-generated constructor stub
}

@Override
public Object postProcessAfterInitialization(Object arg0, String arg1)
        throws BeansException {
    System.out
    .println("BeanPostProcessor 接口方法 postProcessAfterInitialization 对属性进行更改!");
    return arg0;
}

@Override
public Object postProcessBeforeInitialization(Object arg0, String arg1)
        throws BeansException {
    System.out
    .println("BeanPostProcessor 接口方法 postProcessBeforeInitialization 对属性进行更改!");
    return arg0;
}

}

如上,BeanPostProcessor 接口包括 2 个方法 postProcessAfterInitialization 和 postProcessBeforeInitialization,这两个方法的第一个参数都是要处理的 Bean 对象,第二个参数都是 Bean 的 name。返回值也都是要处理的 Bean 对象。这里要注意。

3、InstantiationAwareBeanPostProcessor 接口本质是 BeanPostProcessor 的子接口,一般我们继承 Spring 为其提供的适配器类 InstantiationAwareBeanPostProcessor Adapter 来使用它,如下:
[Java] 纯文本查看 复制代码
?

package springBeanTest;

import java.beans.PropertyDescriptor;

import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;

public class MyInstantiationAwareBeanPostProcessor extends

    InstantiationAwareBeanPostProcessorAdapter {public MyInstantiationAwareBeanPostProcessor() {super();
    System.out
            .println("这是 InstantiationAwareBeanPostProcessorAdapter 实现类构造器!!");
}

// 接口方法、实例化 Bean 之前调用
@Override
public Object postProcessBeforeInstantiation(Class beanClass,
        String beanName) throws BeansException {
    System.out
            .println("InstantiationAwareBeanPostProcessor 调用 postProcessBeforeInstantiation 方法");
    return null;
}

// 接口方法、实例化 Bean 之后调用
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
        throws BeansException {
    System.out
            .println("InstantiationAwareBeanPostProcessor 调用 postProcessAfterInitialization 方法");
    return bean;
}

// 接口方法、设置某个属性时调用
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs,
        PropertyDescriptor[] pds, Object bean, String beanName)
        throws BeansException {
    System.out
            .println("InstantiationAwareBeanPostProcessor 调用 postProcessPropertyValues 方法");
    return pvs;
}

}
这个有 3 个方法,其中第二个方法 postProcessAfterInitialization 就是重写了 BeanPostProcessor 的方法。第三个方法 postProcessPropertyValues 用来操作属性,返回值也应该是 PropertyValues 对象。

4、演示工厂后处理器接口方法,如下:
[Java] 纯文本查看 复制代码
?

package springBeanTest;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

public MyBeanFactoryPostProcessor() {super();
    System.out.println("这是 BeanFactoryPostProcessor 实现类构造器!!");
}

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0)
        throws BeansException {
    System.out
            .println("BeanFactoryPostProcessor 调用 postProcessBeanFactory 方法");
    BeanDefinition bd = arg0.getBeanDefinition("person");
    bd.getPropertyValues().addPropertyValue("phone", "110");
}

}

5、配置文件如下 beans.xml,很简单,使用 ApplicationContext, 处理器不用手动注册:

[XML] 纯文本查看 复制代码
?

<?xml version=”1.0″ encoding=”UTF-8″?>

<beans xmlns=”http://www.springframework.org/schema/beans”

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">

<bean id="beanPostProcessor" class="springBeanTest.MyBeanPostProcessor">
</bean>

<bean id="instantiationAwareBeanPostProcessor" class="springBeanTest.MyInstantiationAwareBeanPostProcessor">
</bean>

<bean id="beanFactoryPostProcessor" class="springBeanTest.MyBeanFactoryPostProcessor">
</bean>
 
<bean id="person" class="springBeanTest.Person" init-method="myInit"
    destroy-method="myDestory" scope="singleton" p:name="张三" p:address="广州"
    p:phone="15900000000" />

</beans>

6、下面测试一下:
[Java] 纯文本查看 复制代码
?

package springBeanTest;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanLifeCycle {

public static void main(String[] args) {System.out.println("现在开始初始化容器");
     
    ApplicationContext factory = new ClassPathXmlApplicationContext("springBeanTest/beans.xml");
    System.out.println("容器初始化成功");    
    // 得到 Preson,并使用
    Person person = factory.getBean("person",Person.class);
    System.out.println(person);
     
    System.out.println("现在开始关闭容器!");
    ((ClassPathXmlApplicationContext)factory).registerShutdownHook();}

}
关闭容器使用的是实际是 AbstractApplicationContext 的钩子方法。

我们来看一下结果:
[HTML] 纯文本查看 复制代码
?

现在开始初始化容器
2014-5-18 15:46:20 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@19a0c7c: startup date [Sun May 18 15:46:20 CST 2014]; root of context hierarchy
2014-5-18 15:46:20 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [springBeanTest/beans.xml]
这是 BeanFactoryPostProcessor 实现类构造器!!
BeanFactoryPostProcessor 调用 postProcessBeanFactory 方法
这是 BeanPostProcessor 实现类构造器!!
这是 InstantiationAwareBeanPostProcessorAdapter 实现类构造器!!
2014-5-18 15:46:20 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@9934d4: defining beans [beanPostProcessor,instantiationAwareBeanPostProcessor,beanFactoryPostProcessor,person]; root of factory hierarchy
InstantiationAwareBeanPostProcessor 调用 postProcessBeforeInstantiation 方法
【构造器】调用 Person 的构造器实例化
InstantiationAwareBeanPostProcessor 调用 postProcessPropertyValues 方法
【注入属性】注入属性 address
【注入属性】注入属性 name
【注入属性】注入属性 phone
【BeanNameAware 接口】调用 BeanNameAware.setBeanName()
【BeanFactoryAware 接口】调用 BeanFactoryAware.setBeanFactory()
BeanPostProcessor 接口方法 postProcessBeforeInitialization 对属性进行更改!
【InitializingBean 接口】调用 InitializingBean.afterPropertiesSet()
【init-method】调用 <bean> 的 init-method 属性指定的初始化方法
BeanPostProcessor 接口方法 postProcessAfterInitialization 对属性进行更改!
InstantiationAwareBeanPostProcessor 调用 postProcessAfterInitialization 方法
容器初始化成功
Person [address= 广州, name= 张三, phone=110]
现在开始关闭容器!
【DiposibleBean 接口】调用 DiposibleBean.destory()
【destroy-method】调用 <bean> 的 destroy-method 属性指定的初始化方法
更多技术资讯可关注:gzitcast

退出移动版