容器扩展点:后置处理器BeanPostProcessor
来源:互联网 发布:网络赢钱游戏 编辑:程序博客网 时间:2024/04/28 16:38
本文转自点击打开链接
综述
先回顾bean生命周期的这张图,看看BeanPostProcessor调用位置
通过上图看到BeanPostProcessor(Bean后置处理器)两个方法在bean生命周期的位置,即:在Spring容器完成Bean实例化和属性设置后,并且在bean调用初始化方法之前或之后。因此BeanPostProcessor(Bean后置处理器)常用在:对bean内部的值进行修改;实现Bean的动态代理等。
可以定义一个或者多个BeanPostProcessor接口的实现,然后注册到容器中。那么该容器里管控的所有Bean在调用初始化方法之前或之后,都会调用BeanPostProcessor接口中对应的方法。
InstantiationAwareBeanPostProcessor是BeanPostProcessor的子接口。从最上面的生命周期图,我们知道它在Bean生命周期的另外三个时期提供扩展的回调接口。其使用方法与BeanPostProcessor接口类似,只时回调时机不同。
BeanPostProcessor接口有两个方法:
Object postProcessBeforeInitialization(Object bean,String BeanName)throws BeansException;
- 1
Object postProcessAfterInitialization(Object bean,String BeanName)throws BeansException;
- 1
容器调用接口定义的方法时会将该受管Bean的实例和名字通过参数传入方法,经过处理后通过方法的返回值返回给容器。注意,不能返回null,如果返回的是null那么我们通过getBean方法将得不到目标。
BeanPostProcessor不允许标记为延迟加载。因为如果这样做,Spring容器将不会注册它们,自定义逻辑也就无法得到应用。假如你在<beans />
元素的定义中使用了'default-lazy-init'
属性,那就必须将每个BeanPostProcessor显示标记为'lazy-init="false"'
。
如果定义了多个BeanPostProcessor,可以在xml配置中通过order属性来指定执行的顺序。
简单例子
类代码:(在这个例子中,可以不需要继承接口。但为了保持和原来的程序一致,就没有删implements PlayerActionInterface
了):
package twm.spring.LifecycleTest;public class footballPlayer implements PlayerActionInterface{{ String name;//球员名字 String team;//所在球队 //getter and setter...... public void shoot() { System.out.println(this.getName()+"射门"); } public void pass() { System.out.println(this.getName()+"边路传中"); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
注册:
<bean id="cluo" class="twm.spring.LifecycleTest.footballPlayer"> <property name="name" value="C.罗纳尔多"></property></bean>
- 1
- 2
- 3
这是原来的程序。调用:
public static void main(String[] args) throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); footballPlayer smone = ctx.getBean("cluo",footballPlayer.class); smone.shoot(); smone.pass();}
- 1
- 2
- 3
- 4
- 5
- 6
输出:
C.罗纳尔多射门
C.罗纳尔多边路传中
现在我们加入一个beanPostProcessor后处理器(beanPostProcessorImpl.java),修改球员名称:
package twm.spring.LifecycleTest;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanPostProcessor;public class beanPostProcessorImpl implements BeanPostProcessor{ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if(bean instanceof footballPlayer){ ((footballPlayer) bean).setName("Messi"); } return bean; } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
配置文件beans.xml加上:
<bean class="twm.spring.LifecycleTest.beanPostProcessorImpl" />
- 1
其它不变,这时再运行,输出:
Messi射门
Messi边路传中
代理使用例子
在刚才的例子基础上,有新的需求:教练团队需要在每一次调用pass(),shoot()方法时,记录调用时间,用来进行战术分析。
于是重写beanPostProcessor后处理器(beanPostProcessorImpl.java)
代码如下:
public class beanPostProcessorImpl implements BeanPostProcessor{ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { /* 后处理器beanPostProcessor会对容器中所有的bean起作用,因此我们要限定一下范围。 * 这个例子中,我们只处理PlayerActionInterface对象*/ if(!(bean instanceof PlayerActionInterface)){ return bean; } final Object finalBean=bean; Map map = new ConcurrentHashMap(100); if(map.get(beanName)!=null){ return map.get(beanName); } Class[] classes=bean.getClass().getInterfaces(); if(classes.length<1){ //没有接口的,无法进行代理 return bean; } Object proxyObj = Proxy.newProxyInstance(this.getClass().getClassLoader(), classes, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("method:" + method.getName()); Object result = method.invoke(finalBean, args); System.out.println("发生时间:" + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")) .format(new Date())); return result; } }); map.put(beanName, proxyObj); return proxyObj; } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
业务调用代码要将以前的类声明改成接口声明PlayerActionInterface,
因此调整为:
public static void main(String[] args) throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); PlayerActionInterface smone = ctx.getBean("cluo",PlayerActionInterface.class); smone.shoot(); smone.pass();}
- 1
- 2
- 3
- 4
- 5
- 6
这时再运行代码输出:
method:shoot
C.罗纳尔多射门
发生时间:2017-03-31 14:09:02
method:pass
C.罗纳尔多边路传中
发生时间:2017-03-31 14:09:02
补充:
当然也可以用beanPostProcessor实现AOP代理。
后置处理器BeanPostProcessor对上一篇提到的FactoryBean产生的bean也是有效的(双重代理)。
如果我们把刚才定义的beanPostProcessorImpl类注册到上一篇的例子中去,就会输出:
getObject
ctx.getBean(“playerfacory”):com.sun.proxy.$Proxy1
ctx.getBean(“&playerfacory”):twm.spring.LifecycleTest.PlayerFactory-----------------------
method:shoot
method:shoot
观察进攻及防守队员跑位
method:shoot
C.罗纳尔多射门
发生时间:2017-03-31 15:22:07
无球跑动
发生时间:2017-03-31 15:22:07
method:pass
method:pass
观察进攻及防守队员跑位
method:pass
C.罗纳尔多边路传中
发生时间:2017-03-31 15:22:07
无球跑动
发生时间:2017-03-31 15:22:07
但是有个超出预料的,就是每一个方法调用都多出了一个:“发生时间:2017-03-31 15:22:07”。这怎么回事呢?
后面有空再研究。
- 容器扩展点:后置处理器BeanPostProcessor
- 【Spring学习23】容器扩展点:后置处理器BeanPostProcessor
- 【Spring学习24】容器扩展点:后置处理器BeanFactoryPostProcessor
- Spring容器扩展点之BeanPostProcessor
- Spring中的后置处理器BeanPostProcessor讲解
- spring-扩展点-BeanPostProcessor
- spring 后置处理器BeanFactoryPostProcessor和BeanPostProcessor的用法和区别
- Spring的后置处理器(BeanFactoryPostProcessor和BeanPostProcessor)
- spring 后置处理器BeanFactoryPostProcessor和BeanPostProcessor的用法和区别
- spring 后置处理器BeanFactoryPostProcessor和BeanPostProcessor的用法和区别
- spring 后置处理器BeanFactoryPostProcessor和BeanPostProcessor的用法和区别
- spring 后置处理器BeanFactoryPostProcessor和BeanPostProcessor的用法和区别
- spring 后置处理器BeanFactoryPostProcessor和BeanPostProcessor的用法和区别
- spring 后置处理器BeanFactoryPostProcessor和BeanPostProcessor的用法和区别
- 无处不在的扩展点BeanPostProcessor
- spring扩展容器-ApplicationContext之BeanPostProcessor
- 关于Spring的Aware接口和后置处理器接口(BeanPostProcessor和BeanFactoryPostProcessor)的一些想法
- Spring开闭原则的表现-BeanPostProcessor的扩展点-1
- javaweb图片上传 tomcat重新部署 图片消失
- 多张图片上传服务器
- [线段树]HDU 4942——Game on S♂play
- 第五周项目2——建立链栈算法库
- python自学(1)-安装环境及工具、学习教程资料的准备
- 容器扩展点:后置处理器BeanPostProcessor
- 376
- input=file 通过Ajax上传
- Redis理解
- [日推荐]『拉勾招聘』手机APP可以卸掉啦!
- 手机联网状态
- 3S基础知识:GIS中的坐标系定义与转换
- ATLANT——全球房地产区域链平台
- Android 6.0以后权限申请问题