Spring 与 Cglib代理的诡异问题

Spring 与 Cglib代理的诡异问题

问题描述:

一个普通的业务对象 没有实现接口 通过cglib代理
[code="java"]public class UserDao {

public void a() {
    System.out.println("aa");
}

public void b() {
    System.out.println("bb");
}

public void c() {
    this.a();
    this.b();
}

}[/code]

这是实现了cglib的一个接口 以完成方法的拦截
[code="java"]public class T implements MethodInterceptor{

@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2,
        MethodProxy arg3) throws Throwable {
    System.out.println("before");
    return arg3.invokeSuper(arg0, arg2);
}

}[/code]

[code="java"]
public static void main(String[] args) {
Enhancer en = new Enhancer();
en.setSuperclass(UserDao.class);
en.setCallbacks(new Callback[]{new T()});
UserDao dao = (UserDao) en.create();
dao.c();
}
[/code]
//这是通过CGLIB代理的测试 输出结果如下
before
before
aa
before
bb
每个方法都被拦截了 接下来问题来了

[code="java"] public static void main(String[] args) {
BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-aop.xml");
UserDao dao = (UserDao) beanFactory.getBean("userdao");
dao.c();
}[/code]

[code="java"] public void actionAop() {
System.out.println("ControllerAopHandler.actionAop()");
}[/code]

[code="java"]

<aop:config>
    <aop:aspect id="controllerAspect" ref="controllerAopHandler" order="1">
        <aop:pointcut expression="execution(* com.gary.operation.demo.UserDao.*(..))" id="allMethod"/>
        <aop:before method="actionAop" pointcut-ref="allMethod"/>
    </aop:aspect>
</aop:config> [/code]

这个代理对象是通过Spring容器拿出来的。那么因为没用使用接口 所以底层还是使用Cglib 但是输入结果却有所不同。

这是输出结果
ControllerAopHandler.actionAop()
aa
bb
[size=small][color=red]也就是说C方法被拦截了 而a,b方法没有被拦截, 单独调用A,B方法均被拦截,那么后来我分析问题大概是出在这个地方[/color][/size]

[code="java"] public void c() {
//如果是通过cglib创建的代理 那么这里的this 还是指向代理对象
//所以当this.a的时候 还是通过UserDao$$EnhancerByCGLIB$$9e419b6.a()方法
//所以被拦截了
//反之就是用Spring创建的代理对象 那么这里的this 就变成了目标对象 所以没有被拦截
//我就不明白了 这到底是咋回事呢?
System.out.println(this);
this.a();
this.b();
}[/code]

真心请教Spring高手给指点一二

你使用的问题
arg3.invokeSuper(arg0, arg2); (这样强制掉父类了)
应该是
arg3.invoke(arg0, arg2); (而且此处不应该是arg0 而应该传入目标对象)

你可以参考下我博客的 怎么写代理 和 aop可能遇到的自我调用问题
[url]http://jinnianshilongnian.iteye.com/blog/1474325[/url]
[url]http://jinnianshilongnian.iteye.com/blog/1487235[/url]