AOP的XML配置:配置了两个BeanNameAutoProxyCreator,会怎么样?

在配置Spring AOP时,可以使用

org.springframework.aop.framework.autoproxy.BeanNameAutoproxyCreator

来完成目标服务的拦截
比如:

<bean id="serviceInteceptorProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoproxyCreator">
        <property name="interceptorNames">
            <list>
                <value>helloServiceAOP</value>
            </list>
        </property>
        <property name="beanNames">
            <value>
                helloService
            </value>
        </property>
    </bean>
    <bean id="helloServiceAOP" class="com.bing.aoptest.aop.HelloServiceAOP" />
    <bean id="helloService" class="com.bing.aoptest.service.HelloServiceImpl"></bean>

会在helloService的方法执行之前,先执行helloServiceAOP。
HelloServiceImpl定义如下:

package com.bing.aoptest.service;

public class HelloServiceImpl implements HelloService {

    public void say() {
        System.out.println("Hello");
    }

}

HelloServiceAOP定义如下:

package com.bing.aoptest.aop;

import java.lang.reflect.Method;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class HelloServiceAOP implements MethodInterceptor {

    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("\nHelloServiceAOP: "
                + invocation.getmethod().getDeclaringClass().getName());
        return invocation.proceed();//放行,调用目标方法
    }

}

那么,如果定义了两个BeanNameAutoproxyCreator会怎么样呢?
xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean id="helloService" class="com.bing.aoptest.service.HelloServiceImpl"></bean>

    <bean id="serviceInteceptorProxyCreator2" class="org.springframework.aop.framework.autoproxy.BeanNameAutoproxyCreator">
        <property name="interceptorNames">
            <list>
                <value>helloServiceInterceptor</value>
            </list>
        </property>
        <property name="beanNames">
            <value>
                helloService
            </value>
        </property>
    </bean>

    <bean id="serviceInteceptorProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoproxyCreator">
        <property name="interceptorNames">
            <list>
                <value>helloServiceAOP</value>
            </list>
        </property>
        <property name="beanNames">
            <value>
                helloService
            </value>
        </property>
    </bean>
    <bean id="helloServiceAOP" class="com.bing.aoptest.aop.HelloServiceAOP" />
    <bean id="helloServiceInterceptor" class="com.bing.aoptest.aop.HelloServiceInterceptor" />
</beans>

helloServiceAOP和helloServiceInterceptor都拦截目标对象,但定义在不同的BeanNameAutoproxyCreator里面。

helloServiceAOP定义如下:

package com.bing.aoptest.aop;

import java.lang.reflect.Method;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class HelloServiceAOP implements MethodInterceptor {

public Object invoke(MethodInvocation invocation) throws Throwable {
    System.out.println("\nHelloServiceAOP: "
            + invocation.getmethod().getDeclaringClass().getName());
    Method m = AOPUtil.getmethod(invocation);
    System.out.println("HelloServiceAOP,method对象:" + m);
    System.out.println("HelloServiceAOP,invocation对象:" + invocation);
    return invocation.proceed();
}

}

helloServiceInterceptor定义如下:

package com.bing.aoptest.aop;

import java.lang.reflect.Method;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class HelloServiceInterceptor implements MethodInterceptor {

    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("\nHelloServiceInterceptor: "
                + invocation.getmethod().getDeclaringClass().getName());
        Method m = AOPUtil.getmethod(invocation);
        System.out.println("HelloServiceInterceptor,method对象:" + m);

        System.out.println("HelloServiceInterceptor,invocation对象:"
                + invocation);
        return invocation.proceed();
    }

}

调用方法

package com.bing.aoptest;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClasspathXmlApplicationContext;

import com.bing.aoptest.service.HelloService;

/** * Hello World! * */
public class App {
    public static void main(String[] args) {
        ApplicationContext context = new ClasspathXmlApplicationContext(
                "applicationContext.xml");
        HelloService hs = (HelloService) context.getBean("helloService");
        hs.say();

    }
}

输出结果:

HelloServiceAOP: com.bing.aoptest.service.HelloService
HelloServiceAOP,method对象:public final void com.sun.proxy.$Proxy0.say()
HelloServiceAOP,invocation对象:ReflectiveMethodInvocation: public abstract void com.bing.aoptest.service.HelloService.say(); target is of class [com.sun.proxy.$Proxy0]

HelloServiceInterceptor: com.bing.aoptest.service.HelloService
HelloServiceInterceptor,method对象:public void com.bing.aoptest.service.HelloServiceImpl.say()
HelloServiceInterceptor,invocation对象:ReflectiveMethodInvocation: public abstract void com.bing.aoptest.service.HelloService.say(); target is of class [com.bing.aoptest.service.HelloServiceImpl]
Hello

请注意
HelloServiceAOP,method对象:public final void com.sun.proxy.$Proxy0.say()
HelloServiceInterceptor,method对象:public void com.bing.aoptest.service.HelloServiceImpl.say()

为什么method对象不都是public void com.bing.aoptest.service.HelloServiceImpl.say()呢?

原因
定义了两个org.springframework.aop.framework.autoproxy.BeanNameAutoproxyCreator,按照顺序分别计作A,B,A会为目标对象T生成代理对象P1,B会为P1生成代理对象P2,代理逻辑就变成:
P2代理P1,P1代理T,而不是P2、P1都代理T。

所以,调用T的方法时,应该先执行P1,但P2代理了P1,最终先执行P2,再执行P1,在执行T。

这种情况下,如果T的方法上有注解,只有P1能够拿到注解信息,P2是拿不到的。

所以,不要定义个多个org.springframework.aop.framework.autoproxy.BeanNameAutoproxyCreator的bean。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


php输出xml格式字符串
J2ME Mobile 3D入门教程系列文章之一
XML轻松学习手册
XML入门的常见问题(一)
XML入门的常见问题(三)
XML轻松学习手册(2)XML概念
xml文件介绍及使用
xml编程(一)-xml语法
XML文件结构和基本语法
第2章 包装类
XML入门的常见问题(二)
Java对象的强、软、弱和虚引用
JS解析XML文件和XML字符串详解
java中枚举的详细使用介绍
了解Xml格式
XML入门的常见问题(四)
深入SQLite多线程的使用总结详解
PlayFramework完整实现一个APP(一)
XML和YAML的使用方法
XML轻松学习总节篇