开发者社区 问答 正文

Spring 与 Cglib代理的诡异问题

一个普通的业务对象 没有实现接口 通过cglib代理 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();  
    }  
}

这是实现了cglib的一个接口 以完成方法的拦截 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);  
    }  
  
}

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();  
}

//这是通过CGLIB代理的测试 输出结果如下 before before aa before bb 每个方法都被拦截了 接下来问题来了

Java代码 收藏代码

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

Java代码 收藏代码

public void actionAop() {  
    System.out.println("ControllerAopHandler.actionAop()");  
}

Java代码 收藏代码

<bean id="userdao" class="com.gary.operation.demo.UserDao"></bean>  
<bean id="controllerAopHandler" class="com.gary.base.aop.ControllerAopHandler" />  
  
<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>

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

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

Java代码 收藏代码

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

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

展开
收起
长安归故里. 2020-01-07 14:11:53 857 分享 版权
1 条回答
写回答
取消 提交回答
  • 你使用的问题 arg3.invokeSuper(arg0, arg2); (这样强制掉父类了) 应该是 arg3.invoke(arg0, arg2); (而且此处不应该是arg0 而应该传入目标对象)

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

    2020-01-07 14:12:07
    赞同 展开评论