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的具体调用顺序,举一个例子说明。
这个例子里面可以看到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对象做个动态代理。
先给出具体代码我在做分析:
做动态代理必须要接口,所以我先给出抽象角色(接口)
再给出真实角色:
再给出实现了BeanPostProcessor接口的方法:
再给出Spring的配置文件(applicationContext.xml)
最后给出Junit的测试代码
对上面代码的分析:经过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();每一次执行方法时都会被动态代理所拦截,从而执行了三次动态代理。
这个接口两个方法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();每一次执行方法时都会被动态代理所拦截,从而执行了三次动态代理。
相关文章推荐
- java7新特新(一) Try-with-resources (TWR)
- 生产消费者4 - 实现一个基于优先级的传输队列【消费顺序是由优先级决定的而不是抵达时间】
- Maven 指定JDK版本
- jdk jre java虚拟机 GCjava回收机制
- Java 浅析内部类
- Hibernate学习笔记之在Eclipse上手动配置Hibernate文件
- 22、关于Drools Web版本与java实现自动扫描功能
- 获得指定时间的下一天的N种方法
- 如何用java生成随机验证码
- Java重写与重载
- java 读取 Properties
- JAVA学习日志(8-1-多态)
- Java判断一个时间是否在另一个时间段内
- 浅谈java内部类
- 一个简单的java提取页面源码的示例
- 21、关于Drools Web版本与java实现简单交互
- 【java虚拟机序列】java中的垃圾回收与内存分配策略
- 【java虚拟机序列】java中的垃圾回收与内存分配策略
- 安卓java.lang.IllegalArgumentException: The observer is null.解决方案
- 安卓java.lang.IllegalArgumentException: The observer is null.解决方案