深入字节码理解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. Selenium+python入门

    在 WebDriver 中, 将这些关于鼠标操作的方法封装在 ActionChains 类提供 ActionChains 类提供了鼠标操作的常用方法: perform(): 执行所有 ActionCh ...

  2. canvas 实现弹跳效果

    一:创建画布 <canvas width="600" height="600" id="canvas"></canvas& ...

  3. mysql explain中的type列含义和extra列的含义

    很多朋友在用mysql进行调优的时候都肯定会用到explain来看select语句的执行情况,这里简单介绍结果中两个列的含义. 1 type列 官方的说法,说这列表示的是“访问类型”,更通俗一点就是: ...

  4. java JNI 实现原理 (二) Linux 下如何 load JNILibrary

    在博客java JNI (一)虚拟机中classloader的JNILibrary 中讨论了java中的Library 是由classloader 来load的,那我们来看看 classloader是 ...

  5. vue 开发系列(七) 路由配置

    概要 用 Vue.js + vue-router 创建单页应用,是非常简单的.使用 Vue.js ,我们已经可以通过组合组件来组成应用程序,当你要把 vue-router 添加进来,我们需要做的是,将 ...

  6. hdu6444 2018中国大学生程序设计竞赛 - 网络选拔赛 1007 Neko's loop

    Neko's loop Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total S ...

  7. SpringBoot2.0.2 不使用parent作为maven单继承方式操作 : org.springframework.boot : spring-boot-dependencies : 2.0.2.RELEASE

    1.pom配置方式 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="h ...

  8. std::string的find问题研究

    https://files-cdn.cnblogs.com/files/aquester/std之string的find问题研究.pdf 目录 目录 1 1. 前言 1 2. find字符串 1 3. ...

  9. python advanced programming ( I )

    函数式编程 函数是Python内建支持的一种封装,通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计.函数就是面向过程的程序设计的基 ...

  10. mui学习

      改变状态栏的颜色 <meta name="apple-mobile-web-app-capable" content="yes"> <me ...