深入字节码理解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. kbmMW均衡负载与容灾(1)(转载红鱼儿)

    kbmMW为均衡负载与容灾提供了很好的机制,支持多种实现方式,现在看看最简单的一种,客户端控制的容灾和简单的负载均衡. 现在,我们将kbmMWServer部署到不同的服务器,或者在同一服务器部署多份实 ...

  2. AOP (切点表达式讲解)

    Spring EL表达式:: 1.execution 表达式 语法格式: execution(返回类型.包名.类名.方法名(参数表)) exection(*.com.xxx.AService.*(.. ...

  3. ios 数组和字典

    一.数组.  数组只能存放对象类型的数据  2.数组中的对象是有序的 (index)     (一)可变数组   NSArray:NSObject  不可变数组 作用:容器类 存放的是对象类型的数据, ...

  4. 2018.11.01 NOIP训练 树的排列(树形dp)

    传送门 跟这道题差不多. 只不过是让权值小的儿子做权值大的儿子的父亲而已. 代码

  5. php $_SERVER中的一些选项说明

    1, $_SERVER['SCRIPT_FILENAME'] 和 常量 __FILE__的区别(一般情况下两者的显示相同,都是显示文件的绝对路径,包括文件名,显示的起点是 电脑根目录 /) ①,如果在 ...

  6. UVa 10294 Arif in Dhaka (First Love Part 2) (Polya定理)

    题意:给定 n 和 m 表示要制作一个项链和手镯,项链和手镯的区别就是手镯旋转和翻转都是相同的,而项链旋转都是相同的,而翻转是不同的,问你使用 n 个珠子和 m 种颜色可以制作多少种项链和手镯. 析: ...

  7. 时间控件My97简单用法

    my97的用法很是简单,项目中用到,查了资料才找到的,简单使用,记一下,方便查阅. 1.添加依赖. <script language="javascript" type=&q ...

  8. 笔记 Bioinformatics Algorithms Chapter2

    Chapter2 WHICH DNA PATTERNS PLAY THE ROLE OF MOLECULAR CLOCKS 寻找模序 一. 转录因子会结合基因上游的特定序列,调控基因的转录表达,但是在 ...

  9. golang web sample

    一.学习想法 用两天的时间学习golang,但这次是先不看书的,直接写代码先. 我们常习惯边看书边学习写代码,但发现过程是比较缓慢的,所以我就先想写代码, 边写边查.就我们所知,web app一般是基 ...

  10. 学习protobuf 感想

    前俩篇博文是从大牛的博客抄过来的, 写的都很好. 这里还写简单写下自己的感想: 1. 和json比, protobuff编码后的体积小很多, 这是肯定的. 都源自于protobuff内部的一系列特殊的 ...