一、bean的声明周期
IOC容器在管理bean时,是遵循一整套流程的,bean在IOC容器中从创建到销毁流程如下:
- 初始化IOC容器
- 通过构造器或工厂方法创建bean的实例
- 为bean的属性设置值或者对其它bean的引用
- 调用bean设置的初始化方法
- 使用bean
- 容器关闭时,调用bean的销毁方法,然后关闭容器
下面通过简单实例演示下:
1、首先创建一个bean的类Person
public class Person {
private String name;
/*2、调用构造器方法*/
public Person() {
System.out.println("hello ..." + name);
}
/*bean的初始化方法*/
/*4、执行bean的初始化方法*/
public void initMethod(){
System.out.println("initMethod...");
}
/*bean的销毁方法*/
/*6、执行bean的销毁方法*/
public void destroyMethod(){
System.out.println("destroyMethod ...");
}
public String getName() {
return name;
}
/*3、为bean的属性赋值*/
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person [name=" + name + "]";
}
}
2、spring的配置文件bean.xml配置如下:
<!--init-method属性指定了调用的初始化方法;destroy-method指定了销毁bean时调用的销毁方法-->
<bean id="person" class="com.lzj.spring.Person"
init-method="initMethod" destroy-method="destroyMethod">
<property name="name" value="lzj"></property>
</bean>
3、测试方法如下:
public class SpringTest {
public static void main(String[] args) {
System.out.println("IOC");
/*初始化IOC容器*/
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext("bean.xml");
/*5、使用bean*/
Person person = (Person) ctx.getBean("person");
System.out.println(person);
/*7、关闭容器*/
ctx.close();
}
}
4、输出结果如下:
IOC-----------
hello ...null
initMethod...
Person [name=lzj]
destroyMethod ...
运行顺序的7个步骤已在上面程序进行标记。
二、创建bean的后置处理器对bean的声明周期影响
创建bean的后置处理器需要实现BeanPostProcessor接口,该接口中有两个方法需要实现:
public Object postProcessAfterInitialization(Object bean, String beanName);
public Object postProcessBeforeInitialization(Object bean, String beanName);
bean为bean的示例对象,beanName为bean的实例对象名,即bean标签中id名。postProcessBeforeInitialization方法在初始化方法initMethod的前调用;postProcessAfterInitialization方法在initMethod初始化方法之后进行调用。如果bean中没有定义初始化方法,则在构造器方法之后调用postProcessBeforeInitialization方法,然后调用postProcessAfterInitialization方法,然后使用bean。
注意: 一旦创建了后置处理器,后置处理器中的两个方法会在每一个bean的初始化方法前后执行,因此若要指定后置处理器只在指定的bean上执行,需要的postProcessAfterInitialization和postProcessBeforeInitialization方法中进行判断。示例如下
1、创建一个bean的类Person(与前面一样)
public class Person {
private String name;
/*2、调用构造器方法*/
public Person() {
System.out.println("hello ..." + name);
}
/*bean的初始化方法*/
/*4、执行bean的初始化方法*/
public void initMethod(){
System.out.println("initMethod...");
}
/*bean的销毁方法*/
/*6、执行bean的销毁方法*/
public void destroyMethod(){
System.out.println("destroyMethod ...");
}
public String getName() {
return name;
}
/*3、为bean的属性赋值*/
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person [name=" + name + "]";
}
}
2、创建一个后置处理器MyBeanPostProcessor
package com.lzj.spring;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("initMethod方法调用前。。。");
System.out.println(bean + ":" + beanName);
return bean;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("initMethod方法调用后。。。");
System.out.println(bean + ":" + beanName);
return bean;
}
}
3、spring的配置文件bean.xml为
<bean id="person" class="com.lzj.spring.Person">
<property name="name" value="lzj"></property>
</bean>
<bean class="com.lzj.spring.MyBeanPostProcessor"></bean>
4、输出结果如下:
IOC-----------
hello ...null
initMethod方法调用前。。。
Person [name=lzj]:person
initMethod...
initMethod方法调用后。。。
Person [name=lzj]:person
Person [name=lzj]
destroyMethod ...
可见后置处理器中的两个方法分别在initMethod初始化方法的前后进行执行的。bean的声明周期变为:
- 初始化IOC容器
- 通过构造器或工厂方法创建bean的实例
- 为bean的属性设置值或者对其它bean的引用
- 将 Bean 实例传递给 Bean 后置处理器的 postProcessBeforeInitialization 方法
- 调用bean设置的初始化方法
- 将 Bean 实例传递给 Bean 后置处理器的 postProcessAfterInitialization方法
- 使用bean
- 容器关闭时,调用bean的销毁方法,然后关闭容器
注意:当在spring配置文件中定义时,我们在测试文件中获取IOC容器,用getBean方法从容器中获取bean时,获取到的是名字为person的bean。我们可以在后置处理器中的两个方法中进行修改bean,那么用getBean方法从容器中获取到的bean就是修改后的bean了。例如:
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("initMethod方法调用后。。。");
<!--该方法获取的bean为postProcessBeforeInitialization放回的bean,即为person2,注意,beanName还是在配置文件中配置的id="person"-->
System.out.println(bean + ":" + beanName);
return bean;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("initMethod方法调用前。。。");
System.out.println(bean + ":" + beanName);
<!--在初始化方法前,该方法截取了名字为person的bean,然后穿件了一个新的bean person2,用该bean取代了personbean,然后返回person2的bean-->
if(beanName.equals("person")){
Person person2 = new Person();
person2.setName("Jenken");
bean = person2;
}
return bean;
}
}
测试方法:
public class SpringTest {
public static void main(String[] args) {
System.out.println("IOC-----------");
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext("bean.xml");
Person person = (Person) ctx.getBean("person");
System.out.println(person);
ctx.close();
}
}
输出结果为:
IOC-----------
hello ...null
initMethod方法调用前。。。
Person [name=lzj]:person
hello ...null
person2---
initMethod...
initMethod方法调用后。。。
Person [name=Jenken]:person
Person [name=Jenken]
destroyMethod ...
可见在postProcessBeforeInitialization方法中修改了bean,在postProcessAfterInitialization方法中获取到的bean,以及在后面用getBean方法从容器中获取的bean都是修改过后的bean了。说明,postProcessBeforeInitialization方法中获取已有的Person bean,然后用新的bean去取到了IOC中的person bean。注意,bean的名字还是保持不变的,还是用之前的名字从容器中获取bean就可以了。当然也可以在postProcessAfterInitialization方法中修改bean或者修改bean的属性,然后取代IOC容器中存在的bean,后面用getBean从IOC容器获取的bean依然是修改后的bean。