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的方式。

阅读全文
0 0