Spring入门(AOP API、ProxyFactoryBean其二)
来源:互联网 发布:在java当中interface 编辑:程序博客网 时间:2024/05/20 23:38
ProxyFactoryBean
这个类是Spring AOP代理的最基础核心的一个类
创建Spring AOP代理的基本方法是使用org.springframework.aop.framework.ProxyFactoryBean这个类
通过使用这个类可以完全控制切入点和通知(advice)以及他们的顺序
ProxyFactoryBean和其他的FactoryBean(工厂方法)是一样的,都引入了一个中间层。
假如定义了一个bean的id为foo的ProxyFactoryBean实例,那么引用foo这个对象看到的将不是这个ProxyFactoryBean本身,而是ProxyFactoryBean这个类实现里getObject()方法创建的对象。
getObject方法将创建一个AOP代理包装一个目标对象。
ProxyFactoryBean就是通过这种方式达到了代理的目的。
使用ProxyFactoryBean或者其他IOC相关类来创建AOP代理的最重要好处是通知和切入点也可以由IOC来管理。
被代理类没有实现任何接口,使用CGLIB代理,否则JDK代理。
通过设置proxyTargetClass为true,可强制使用CGLIB。
如果目标类实现了一个(或者多个)接口,那么创建代理的类型将依赖ProxyFactoryBean的配置。
如果ProxyFactoryBean的proxyInterfaces属性被设置为一个或者多个全限定接口名(包括包名和类名),基于JDK的代理将被创建。
如果ProxyFactoryBean的proxyInterfaces属性没有被设置,但是目标类实现了一个(或者多个)接口,那么ProxyFactoryBean将自动检测到这个目标类已经实现了至少一个接口,创建一个基于JDK的代理。
然后看一个例子
首先定义一个bean,然后定义一个advisor,在定义一个Interceptor,重点是下边这一段。bean的id是person,id对应的class并不是person对应的类,而是对应的ProxyFactoryBean这个类。然后有一个属性proxyInterfaces指定了Person这个接口。注意一下下边的target指向的是personTarget,这个personTarget是最上边的bean,它是一个具体的Person的实现类PersonImpl。
刚才有说到,在get perspn这个bean的时候,返回的并不是ProxyFactoryBean这个对象,而是ProxyFactoryBean里边getObject()返回的那个对象,那么getObject返回的是什么,返回的就是target对应的personTarget,也就是最上边这个bean的对象。也就是说调用person的时候,返回的是最上边这个bean的对象。
然后再看边的inerceptors,通过ProxyFactoryBean创建代理的时候,可以指定它的Interceptor,interceptorNames是一个集合,可以用list和value共同指定具体的内容。
如果右下角的配置和前边的内容在同一个上下文中,那么这个property的name是person,ref bean=”person”,它引用到的是欠扁的最下边的bean,最终赋值给person这个属性的bean对象将会是最上边的内容。
之前写了很多代码都没有运行,是因为所有代理都是依赖于ProxyFactoryBean创建的,然后我们看一下前边的例子要如何实现。
方法一
先把几个类配置到xml文件中,然后pointcutBean是一开始介绍到pointcut时写的内容。然后使用了DefaultPointcutAdvisor,里边有一个属性pointcut引用了前边的pointcutBean,属性advice引用了moocBeforeAdvice。
重点看一下下边的内容,这里定义了一个bean bizLogicImpl。前边已经配置了实现类,id为bizLogicImplTarget。在下边配置target属性,并且引用bizLogicImplTarget,接下来设置interceptorNames,在list中有四个内容,没有看到beforeAdvice,那是因为它在defaultAdvisor里边引用到了,里边另外引用的pointcutBean匹配sa开头的方法,这暂时只对beforeAdvice有用。
<?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="moocBeforeAdvice" class="com.imooc.aop.api.MoocBeforeAdvice"></bean> <bean id="moocAfterReturningAdvice" class="com.imooc.aop.api.MoocAfterReturningAdvice"></bean> <bean id="moocMethodInterceptor" class="com.imooc.aop.api.MoocMethodInterceptor"></bean> <bean id="moocThrowsAdvice" class="com.imooc.aop.api.MoocThrowsAdvice"></bean> <bean id="bizLogicImplTarget" class="com.imooc.aop.api.BizLogicImpl"></bean> <bean id="pointcutBean" class="org.springframework.aop.support.NameMatchMethodPointcut"> <property name="mappedNames"> <list> <value>sa*</value> </list> </property> </bean> <bean id="defaultAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"> <property name="advice" ref="moocBeforeAdvice" /> <property name="pointcut" ref="pointcutBean" /> </bean> <bean id="bizLogicImpl" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target"> <ref bean="bizLogicImplTarget"/> </property> <property name="interceptorNames"> <list> <value>defaultAdvisor</value> <value>moocAfterReturningAdvice</value> <value>moocMethodInterceptor</value> <value>moocThrowsAdvice</value> </list> </property> </bean> </beans>
然后看一下单元测试的结果
@Test public void testSave() { BizLogic logic = (BizLogic)super.getBean("bizLogicImpl"); logic.save(); }
getBean时候里边的是bizLogicImpl。这里再一次注意一下!!在xml文件中bizLogicImpl它的id对应的是ProxyFactoryBean,我们getBean时候得到的不是ProxyFactoryBean的对象,而是getObject方法返回的,也就是bizLogicImplTarget。
执行单元测试类
没有异常所以没有调用到AfterThrowing。前边有写到sa开头的所有方法,这里方法为save,如果把这个sa改了,比如改为sp,那么执行的时候,除了第一个beforeAdvice的无法执行,其他的并没被影响。因为pointcutBean由defaultAdvisor来使用,defaultAdvisor又对应了一个moocBeforeAdvice。
方法二、三
那么如果我们不使用pointcutBean会是什么样的效果?
看一下下边这种使用方式
<bean id="bizLogicImplTarget" class="com.imooc.aop.api.BizLogicImpl"></bean> <bean id="bizLogicImpl" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>com.imooc.aop.api.BizLogic</value> </property> <property name="target"> <bean class="com.imooc.aop.api.BizLogicImpl"></bean><-- <ref bean="bizLogicImplTarget"/> --> </property> <property name="interceptorNames"> <list> <value>moocBeforeAdvice</value> <value>moocAfterReturningAdvice</value> <value>moocMethodInterceptor</value> <value>moocThrowsAdvice</value> <value>mooc*</value> </list> </property> </bean>
之前的四个advice保持不动,这里没有写出。这种方式和之前有什么不同?
这次有一个属性proxyInterfaces,对应的是BizLogic这个接口。之前的方式没有配置它,那么它会由ProxyFactoryBean自己去发现是不是有实现了接口。这次我们指定了它,那么就一定会走JDK代理。
property target,这种方式是为对象创建代理,对象的类bizLogicImplTarget会实现这个接口。创建了代理,执行的时候,四个Interceptor会被执行,这里没有前边的pointcut,所以所有方法都会被执行。
之所以这里写了法二、三,其实并没有太大区别,区别就在于注释掉的地方。被注释的是和之前一样的写法,上一行则是新的写法。
就是使用匿名内部bean来隐藏目标和代理之间的区别。另外使用内部bean时,把最上边的那个bean也注释掉。推荐匿名内部bean的方式。
- Spring入门(AOP API、ProxyFactoryBean其二)
- Spring入门(AOP API、ProxyFactoryBean其一)
- Spring入门(AOP API,ProxyFactoryBean其三)
- Spring入门(Schema-based AOP其二)
- Spring AOP小测试(ProxyFactoryBean)
- Spring AOP-编程的方式创建代理类(ProxyFactoryBean)
- 浅析Spring AOP源码(十四) 分析ProxyFactoryBean
- Spring Aop(十三)——ProxyFactoryBean创建代理对象
- Spring AOP实现机制(二)--ProxyFactoryBean---将Spring AOP和Spring IoC容器相结合
- Spring AOP之基于ProxyFactoryBean的代理
- Spring -- org.springframework.aop.framework.ProxyFactoryBean
- Spring AOP之ProxyFactoryBean与BeanNameAutoProxyCreator
- Spring学习笔记 —— AOP(面向切面编程) 之使用ProxyFactoryBean实现AOP
- 做一个合格的程序猿之浅析Spring AOP源码(十四) 分析ProxyFactoryBean
- 用ProxyFactoryBean创建AOP代理(转)
- spring aop(五)--ProxyFactoryBean创建代理的实现
- spring 直接使用ProxyFactoryBean 实现AOP 流程小结
- Spring源码分析-初识ProxyFactoryBean(五)
- 17.10.5日报
- web项目整合MongoDb出现No converter found capable of converting from org.bson.types.ObjectId to type Long异常
- 我的py3笔记-基础数据类型
- MAC下登录SSH
- TCP和UDP的区别
- Spring入门(AOP API、ProxyFactoryBean其二)
- listview图片加载错乱的原理和解决方案
- HTTP与HTTPS的联系与区别
- 通过DeviceIoControl获取真实网卡地址
- Failed to start LSB: Bring up/down networking. 虚拟机重启network失败, 解决方案
- 用C语言实现一个简单的Linux壳层(Shell)
- Django--其他常用功能之保留原页面所有内容
- SSH组合工程之-struts2&hibernate(工程下载)
- poj2932:Coneology(扫描线)