在深入字节码理解invokeSuper无限循环的原因中,我们理解的cglib的原理和其中一个合理的调用方式。但是这个调用方式是基于类的,对所有实例生效。实际场景中,我们可能只是希望代理某个具体的实例,而且这个实例会有自己的特有属性。这个时候要怎么做呢?

public class CglibDynamicProxyDemo {

    static class SampleClass {
public void print(){
System.out.println("hello world");
}
} public static void main(String[] args) {
SampleClass sampleClass = new SampleClass();
SampleClass sample = createCglibDynamicProxy(sampleClass);
sample.print();
} private static SampleClass createCglibDynamicProxy(SampleClass delegate) {
Enhancer enhancer = new Enhancer();
enhancer.setCallback(new CglibInterceptor(delegate));
enhancer.setSuperclass(SampleClass.class);
return (SampleClass) enhancer.create();
} private static class CglibInterceptor implements MethodInterceptor { private Object delegate; public CglibInterceptor(Object delegate) {
this.delegate = delegate;
} @Override
public Object intercept(Object o, Method method, Object[] objects, net.sf.cglib.proxy.MethodProxy methodProxy) throws Throwable {
return methodProxy.invokeSuper(delegate, objects);
}
}
}

通常我们会生成一个拦截器类,然后把实例传递进去,调用的时候使用被代理的对象。

执行代码:

Exception in thread "main" java.lang.ClassCastException: com.ym.materials.proxy.CglibDynamicProxyDemo$SampleClass cannot be cast to com.ym.materials.proxy.CglibDynamicProxyDemo$SampleClass$$EnhancerByCGLIB$$db74855e
at com.ym.materials.proxy.CglibDynamicProxyDemo$SampleClass$$EnhancerByCGLIB$$db74855e$$FastClassByCGLIB$$6a2a8700.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at com.ym.materials.proxy.CglibDynamicProxyDemo$CglibInterceptor.intercept(CglibDynamicProxyDemo.java:42)
at com.ym.materials.proxy.CglibDynamicProxyDemo$SampleClass$$EnhancerByCGLIB$$db74855e.print(<generated>)
at com.ym.materials.proxy.CglibDynamicProxyDemo.main(CglibDynamicProxyDemo.java:22)

异常了,why?

通过前面的分析,我们知道invokeSuper调用fci.f2.invoke(fci.i2, obj, args),使用的是第三个生成类SampleClass$$EnhancerByCGLIB$$8ed28f$$FastClassByCGLIB$$520b645b,方法签名是:CGLIB$test$0

通过方法签名的hashcode映射后得到索引为16

 6         case -1659809612:
7 if(var10000.equals("CGLIB$test$0()V")) {
8 return 16;
9 }
10 break;
 
 public class SampleClass$$EnhancerByCGLIB$$8ed28f$$FastClassByCGLIB$$520b645b extends FastClass {

     public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
8ed28f var10000 = (8ed28f)var2;
int var10001 = var1; try {
switch(var10001) {
case 7:
var10000.test();
return null;
case 16:
var10000.CGLIB$test$0();
return null;
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
} throw new IllegalArgumentException("Cannot find matching method/constructor");
}
}

调用的时候,会先进行类型转换。这样问题就来了,我们传入的delegate是一个sampleClasss实例,而不是新生成的对象,所以类型转换出错。所以如果代理具体实例,正确的写法是:

    private static class CglibInterceptor implements MethodInterceptor {

         private Object delegate;

         public CglibInterceptor(Object delegate) {
this.delegate = delegate;
} @Override
public Object intercept(Object o, Method method, Object[] objects, net.sf.cglib.proxy.MethodProxy methodProxy) throws Throwable {
return methodProxy.invoke(delegate, objects);
}
}

总结:

cglib动态代理

如果代理的类本身,需要使用

public Object intercept(Object o, Method method, Object[] objects, net.sf.cglib.proxy.MethodProxy methodProxy) throws Throwable {
return methodProxy.invoke(o, objects);
}

如果代理的是实例,需要使用

public Object intercept(Object o, Method method, Object[] objects, net.sf.cglib.proxy.MethodProxy methodProxy) throws Throwable {
return methodProxy.invoke(delegate, objects);
}
												

cglib invoke 和 invokeSuper 可用的组合的更多相关文章

  1. Cglib invoke以及invokeSuper的一点区别

    简单记录下,解决的一个问题,Cglib的invoke和invokeSuper的区别: 简而言之,invoke方法调用的对象没有增强过,invokeSuper方法调用的对象已经是增强了的,所以会再走一遍 ...

  2. Cglib invoke为什么会死循环?

    目录 Cglib invoke为什么会死循环? 动态代理子类的java文件 动态代理子类实例化过程 动态代理类调用过程 动态代理之MethodProxy.invokeSuper Cglib invok ...

  3. Cglib源码分析 invoke和invokeSuper的差别(转)

    原文 https://blog.csdn.net/makecontral/article/details/79593732 Cglib的实例 本文重在源码的分析,Cglib的使用不再复述. //被代理 ...

  4. 【DP-动态代理】JDK&Cglib

    需求:增强未知方法的代码 简单方案:继承或者聚合 继承,调用方法前后加增强逻辑 聚合 - 静态代理 持有被代理类对象 或者接口 可通过嵌套实现代理的组合 和 装饰器模式很像 高级方案 代理所有的类,不 ...

  5. java代理的深入浅出(二)-CGLIB

    java代理的深入浅出(二)-CGLIB 1.基本原理 CGLIB的原理就是生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法.在子类中拦截所有父类方法的调用,拦截下来交给设置的Me ...

  6. Cglib及其基本使用

    前言 最近一直在看Spring源码,其实我之前一直知道AOP的基本实现原理: 如果针对接口做代理默认使用的是JDK自带的Proxy+InvocationHandler 如果针对类做代理使用的是Cgli ...

  7. Cglib动态代理浅析

    原文同步发表至个人博客[夜月归途] 原文链接:http://www.guitu18.com/se/java/2018-06-29/18.html 作者:夜月归途 出处:http://www.guitu ...

  8. CGLIB动态代理模式

    概念: 第三方技术CGLIB动态代理和JDK代理不同的是,JDK代理需要提供接口,而CGLIB代理不需要: 它只需要一个非抽象类就能实现动态代理 例子: /** * 非抽象类 * @author Ad ...

  9. cglib的使用

    前言 最近一直在看Spring源码,其实我之前一直知道AOP的基本实现原理: 如果针对接口做代理默认使用的是JDK自带的Proxy+InvocationHandler 如果针对类做代理使用的是Cgli ...

随机推荐

  1. LD_LIBRARY_PATH

    LD_LIBRARY_PATH是Linux环境变量名,该环境变量主要用于指定查找共享库(动态链接库)时除了默认路径之外的其他路径. 在linux下可以用export命令来设置这个值,比如 在linux ...

  2. 用python实现数学多元数学方程式计算

    题目:公鸡5元钱一只,母鸡3元钱一只,小鸡3只一块钱,其中公鸡,母鸡,小鸡都必须有,问公鸡,母鸡,小鸡各买多少只刚好凑足100元钱? 一:数学算术分析: x+y+z=100 5x+3y+z/3=100 ...

  3. tms web core 通过URL 传递参数

    一般我们都会通过URL 给服务器传递很多参数,通过参数来决定对应的处理,今天就大概讲一下 如果通过URL 参数实现一些功能. 1.通过参数跳入不同的界面 首先我们先建立一个tms web core 工 ...

  4. vue的子传父

    子组件传值给父组件,需要触发一个事件. 在这个事件里,使用this.$emit("父组件使用的名称","子组件的数据") 在父组件中引用的子组件,在子组件的标签 ...

  5. 微信小程序使用三元表达式切换图片

    1.data里定义切换图片的地址和切换的标识 data:{ show:true, yes:"http://101.89.144.168:9090//files/jk/yd/images/in ...

  6. Spring Boot 入门实践

    一.Eclipse配置Spring Boot环境 1.查看eclipse版本信息: 2.登录:http://spring.io/tools/sts/all 看eclipse对应的插件版本对应的ecli ...

  7. 第08章:MongoDB-CRUD操作--文档--删除

    ①语法 remove()  [2.6以后方法过时] deleteOne() [2.6以后官方推荐] deleteMany() [2.6以后官方推荐] db.collection.remove( < ...

  8. RGB转换成YCbCr

    clear all; close all; clc; img=imread('colorbar.jpg');%('ngc6543a.jpg'); %img=mat2gray(img); %[0,1]; ...

  9. [转]深入理解mysqldump原理

    本文转至:http://blog.csdn.net/cug_jiang126com/article/details/49824471 在mysqldump过程中,之前其实一直不是很理解为什么加了--s ...

  10. 20145232 《Java程序设计》课程总结

    学期总结 实验报告链接汇总 实验一 Java开发环境的熟悉 实验二 Java面向对象程序设计 实验三 敏捷开发与XP实践 实验四 Andoid开发基础 实验五 Java网络编程 代码托管链接 :Jav ...