您的位置:首页 > 编程语言 > Java开发

04Spring_bean 后处理器(后处理Bean),BeanPostProcessor ,bean创建时序,动态代理

2016-07-26 01:27 627 查看
这篇文章很重要,讲解的是动态代理,以及bean创建前后的所发生的事情。介绍一个接口:在Spring构造Bean对象过程中,有一个环节对Bean对象进行 后处理操作 (钩子函数) ----- Spring 提供 BeanPostProcessor 接口。我们可以自定义类,实现 BeanPostProcessor 接口,配置到Spring容器中,在构造对象时,spring容器会调用接口中方法。

这个接口两个方法public Object postProcessAfterInitialization(Object bean, String beanName) 方法以及public Object postProcessBeforeInitialization(final Object bean, String beanName) 这两个方法里面的bean就是spring IO容器创建对象,beanName就是Sring配置文件applicationContext.xml文件里面对应的bean id。

为了说明postProcessBeforeInitialization和postProcessAfterInitialization的具体调用顺序,举一个例子说明。

//applicationContext.xml
<bean id="teacherService" class="cn.csdn.cyclelife.TeacherService"  init-method="init" destroy-method="destroy">
<constructor-arg type="java.lang.Integer" index="0">
<value>20</value>
</constructor-arg>
<property name="name">
<value>Longmanfei</value>
</property>
</bean>
<bean id="postService"class="cn.csdn.cyclelife.PostService"></bean>
//TeacherService bean
public class TeacherService {

private String name;

private Integer age;

public void setName(String name){
System.out.println("----这是teacherservice的set方法----");
this.name=name;
}

public TeacherService(Integer age){
this.age=age;
}

public void init(){
System.out.println("--------这是teacherservice的init的方法-------------");
}

public void destroy(){
System.out.println("---------这是销毁(destroy)方法----------");
}

public void display(){
System.out.println(this.name+"-----------------"+this.age);
}
}
// 实现接口的BeanPostProcessor bean
public class PostService implements BeanPostProcessor{

/**在初始化之后调用这个方法*/
@Override
public Object postProcessAfterInitialization(Object bean, String arg1)
throws BeansException {
System.out.println("----这是init之后执行的方法postProcessAfterInitialization----");
return bean;
}

/**在初始bean之前调用的这个方法 在init方法之前执行,在set方法之后*/
@Override
public Object postProcessBeforeInitialization(Object bean, String arg1)
throws BeansException {
/**instanceof 判断前者是否是后者的一个实例*/
if(bean instanceof TeacherService){
System.out.println("--这是在init之前进行修改bean的属性值--");
/*这里我们不能直接new一个对象 因为bean本身就是一个对象,直接转换就可以了*/
((TeacherService)bean).setName("Longmanfei");
}
System.out.println("---这是init之前执行的方法postProcessBeforeInitialization---");
return bean;
}
}
//Junit 测试方法
public class App {

@Test
public void test1(){
/**加载容器*/
ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"applic*.xml"});
/**调用getbean方法*/
TeacherService ts = (TeacherService) ac.getBean("teacherService");

ts.display();

/**调用close方法关闭bean*/
AbstractApplicationContext aac =(AbstractApplicationContext) ac;
aac.close();
}

}
//这是执行结果(当加载容器的时候会判断是否有实现接口的BeanPostProcessor bean,如果有其他Bean就会按照特定的顺序去执行,并且执行实现接口的bean里的方法)
----这是teacherservice的set方法----
--这是在init之前进行修改bean的属性值--
----这是teacherservice的set方法----
---这是init之前执行的方法postProcessBeforeInitialization---
--------这是teacherservice的init的方法-------------
----这是init之后执行的方法postProcessAfterInitialization----
Longmanfei-----------------20
---------这是销毁(destroy)方法----------


这个例子里面可以看到Spring先会创造bean的实例对象,然后调用postProcessBeforeInitialization,然后再调用init-method="init"方法,然后再调用postProcessAfterInitialization方法。

这里我给一个bean的创建流程图



这个图对上面的例子的代码运行结果给出了很好的解释。(这个博客非常不错http://uule.iteye.com/blog/2094609)

换句话说我们在执行public Object postProcessBeforeInitialization(final Object bean, String beanName)方法时,传入的值bean就是IOC容器已经给我们创建好的对象了,

那么我们可以拿这个对象做什么呢?很重要的一点就是动态代理,我们可以给这个bean对象做个动态代理。

先给出具体代码我在做分析:

做动态代理必须要接口,所以我先给出抽象角色(接口)

package cn.itcast.spring.d_lifecycle;

public interface IHello {
public void sayHello();

public void setup();

public void teardown();
}


再给出真实角色:

package cn.itcast.spring.d_lifecycle;

/**
* Bean对象,初始化和销毁方法 (无返回值、无参数、非静态)
*
* @author seawind
*
*/
public class LifeCycleBean implements IHello {
public LifeCycleBean() {
System.out.println("LifeCycleBean 构造...");
}
//配置文件中init-method="setup"
public void setup() {
System.out.println("LifeCycleBean 初始化...");
}
//配置文件中destroy-method="teardown"

public void teardown() {
System.out.println("LifeCycleBean 销毁...");
}
//被代理的方法
@Override
public void sayHello()
{

System.out.println("hello ,itcast...");

}
}


再给出实现了BeanPostProcessor接口的方法:

package cn.itcast.spring.d_lifecycle;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

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

/**
* 后处理器
*
* @author seawind
*
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
static int a=0;
@Override
/**
* bean 代表Spring容器创建对象
* beanName 代表配置对象对应 id属性
*/

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")) {
System.out.println("后处理器 初始化后执行...");
}
return bean;
}

@Override
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
// 针对bean id 为 lifeCycleBean的对象 进行代理,配置文件中bean的id为lifeCycleBean就做一下处理
if (beanName.equals("lifeCycleBean")) {
System.out.println("后处理器 初始化前执行...");
/*给传进来的bean对象做一个动态代理.bean.getClass().getClassLoader表示要被执行代理的类,也就是我们的IOC容器创建的bean对象。
bean.getClass().getInterfaces()表示我们的要代理的类所实现
的所有的而接口,我们最后new出来的代理类会按照这个参数实现这些所有的接口。这也是为什么动态代理模式必须要用接口的原因了。
new InvocationHandler() {}表示真正要执行的方法。
最后用的是return 就是把生成出来的的代理类返回了。所以执行好这个方法后其实的返回的是new 出来的的代理类,而不是之前的bean对象了。(这句话非常重要)
*/
return Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//模拟代理方法(额外要执行的方法)
System.out.println("执行代理.....");

//执行要真正的方法
return method.invoke(bean, args);

}
});
}
return bean;
}

}


再给出Spring的配置文件(applicationContext.xml)

<bean id="lifeCycleBean" class="cn.itcast.spring.d_lifecycle.LifeCycleBean"
init-method="setup" destroy-method="teardown" />


最后给出Junit的测试代码

package cn.itcast.spring.d_lifecycle;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class LifeCycleTest {
@Test
public void testInitDestroy() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
IHello lifeCycleBean = (IHello) applicationContext.getBean("lifeCycleBean");
System.out.println(lifeCycleBean);
lifeCycleBean.sayHello();

// 必须手动调用 容器销毁的方法 --- web服务器tomcat,自动调用容器销毁
applicationContext.close();
}
}


对上面代码的分析:经过public class MyBeanPostProcessor implements BeanPostProcessor里面的postProcessBeforeInitialization方法后,就是给IOC创建的bean对象进行了动态代理,在Junit的测试代码中。我们执行了 lifeCycleBean.sayHello();就会被动态代理给拦截,执行 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {......}里面的方法.这里的lifeCycleBean已经不是lifeCycleBean.class类型了,而是com.sun.proxy.$Proxy4类型了,要验证这个观点很简单,只要在public class LifeCycleTest 方法中的 lifeCycleBean.sayHello();之前加一句System.out.println(lifeCycleBean);就可以得到验证。

最后给出上述代码的是运行结果:

后处理器 初始化前执行...
执行代理.....
被代理的方法是public abstract void cn.itcast.spring.d_lifecycle.IHello.setup()a的值是1aaaaacn.itcast.spring.d_lifecycle.LifeCycleBeanLifeCycleBean 初始化...
后处理器 初始化后执行...
执行代理.....
被代理的方法是public java.lang.String java.lang.Object.toString()

aaaaacn.itcast.spring.d_lifecycle.LifeCycleBeancn.itcast.spring.d_lifecycle.LifeCycleBean@a0430b6
测试方法中lifeCycleBean的真相是com.sun.proxy.$Proxy4执行代理.....

被代理的方法是public abstract void cn.itcast.spring.d_lifecycle.IHello.sayHello()a的值是3aaaaacn.itcast.spring.d_lifecycle.LifeCycleBeanhello ,itcast...

这里很奇怪,为什么执行了这么多的“执行代理” 原因很简单,因为setup()和 System.out.println(lifeCycleBean)和 lifeCycleBean.sayHello();每一次执行方法时都会被动态代理所拦截,从而执行了三次动态代理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: