在深入字节码理解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;}@Overridepublic 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$$db74855eat 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;
 
 1 public class SampleClass$$EnhancerByCGLIB$$8ed28f$$FastClassByCGLIB$$520b645b extends FastClass {
 2
 3     public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
 4         8ed28f var10000 = (8ed28f)var2;
 5         int var10001 = var1;
 6
 7         try {
 8             switch(var10001) {
 9             case 7:
10                 var10000.test();
11                 return null;
12             case 16:
13                 var10000.CGLIB$test$0();
14                 return null;
15         } catch (Throwable var4) {
16             throw new InvocationTargetException(var4);
17         }
18
19         throw new IllegalArgumentException("Cannot find matching method/constructor");
20     }
21 }

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

 1    private static class CglibInterceptor implements MethodInterceptor {
 2
 3         private Object delegate;
 4
 5         public CglibInterceptor(Object delegate) {
 6             this.delegate = delegate;
 7         }
 8
 9         @Override
10         public Object intercept(Object o, Method method, Object[] objects, net.sf.cglib.proxy.MethodProxy methodProxy) throws Throwable {
11             return methodProxy.invoke(delegate, objects);
12         }
13     }

总结:

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


转载于:https://www.cnblogs.com/yangmengdx3/p/9221806.html

cglib invoke 和 invokeSuper 可用的组合相关推荐

  1. cglib:缺少的手册

    字节码检测库cglib是许多众所周知的Java框架(例如Hibernate (现在不再 ))或Spring最受欢迎的选择,它们可以完成肮脏的工作. 字节码检测允许在Java应用程序的编译阶段之后操作或 ...

  2. Spring的@Configuration使用cglib代理的效果和我自己写的简单实现

    下面的代码,照着复制就能跑起来 今天看了下Spring的@Configuration,即java类配置bean,(这个spring3的新功能,虽然现在已经spring5了,但是这种配置bean的方式也 ...

  3. CGLIB动态代理之intercept函数刨析

    网上搜CGLIB动态代理,几乎所有的博文都只给了示例代码而缺少对代码的解释说明(特别是关键的intercept函数),看完实在是云里雾里.所以,这篇博文将带你从源码的角度来理解intercept函数. ...

  4. Spring原理学习(七)JDK动态代理与CGLIB代理底层实现

    AOP 底层实现方式之一是代理,由代理结合通知和目标,提供增强功能. 除此以外,aspectj 提供了两种另外的 AOP 底层实现: 第一种是通过 ajc 编译器在编译 class 类文件时,就把通知 ...

  5. cglib创建代理对象(1)

    cglib创建代理对象 还是从一个的小demo开始 例子 被代理的类 public class Bean{public String sayHello(String name) {return &qu ...

  6. 静态代理,JDK动态代理和CGLIB代理入门学习

    之前面试时面试官问我:"你知道spring中有哪几种代理吗?" 啊?代理?啥子代理?VPN代理吗?嘿嘿,面试官你要种子直说啊......被刷下来了.好吧,入门学习下代理. 为什么需 ...

  7. 死磕cglib系列之一 cglib简介与callback解析

    简介 cglib是一套java动态代理实现框架,cglib被应用到spring app,hibernate等高级业务框架,spring事务在业务实现类未实现接口的情况下也会使用该技术. 实际上,cgl ...

  8. Spring 面向切面编程 第4关:AOP实现原理-CgLib动态代理

    目录 任务描述 相关知识 代理模式(Proxy) AOP实现的两种方式 CGLIB动态代理步骤 模拟AOP实现 代理类说明 编程要求 测试说明 参考代码 任务描述 我们知道,Spring AOP的主要 ...

  9. Linux 高可用(HA)集群之keepalived+lvs

    一:前言 Keepalived使用的vrrp协议方式,虚拟路由冗余协议 (Virtual Router Redundancy Protocol,简称VRRP);Keepalived的目的是模拟路由器的 ...

最新文章

  1. python mkl freebsd_FreeBSD:在uwsgi中使用python3而不是python2
  2. java 预览zip_java压缩包上传,解压,预览(利用editor.md和Jstree实现)和下载
  3. 转载:tcpdump抓包和Wireshark解包
  4. foobar2000转换APE参数设置
  5. 使用 ListView 控件展示数据
  6. android卡片 弹簧滑动,一种通用式弹簧卡扣的制作方法
  7. 计算机财务模型管理实验内容,财务分析模型实验报告
  8. c语言用分治法求最大最小值,C语言实现分治法实例
  9. 为什么程序员不应该在同一家公司待太久?
  10. vue PC端菜单优化(第一个菜单隐藏的时候,整个菜单都不显示)
  11. bzoj4564: [Haoi2016]地图 仙人掌的圆方树 莫队 分块
  12. 股票筛选。如何查找股票?如何查找潜力股?
  13. ES6 findIndex()返回结果有true,却返回的索引位置一直是-1
  14. Python攻防-截取屏幕并自动发送指定邮箱
  15. linux发展史--Linux学习笔记(一)
  16. “罗永浩抖音首秀”销售数据的可视化大屏是怎么做出来的呢?
  17. Source insight 4.0 显示右边文件
  18. 程序媛人生——专访“龙书”《编译原理》联合作者 Monica S. Lam
  19. 我们分手吧,因为我不是处女!
  20. 双11“静悄悄”,折腾14年终于卷不动了?

热门文章

  1. 只有一流的人才能干出一流的工作,只有具备大量一流的人才的企业才能成为一流的企业...
  2. 野火STM32F103教学视频完整目录(配合霸道-指南者开发板)
  3. 业界谈AI赋能传统金融:精细化、数字化、个性化成三大关键词
  4. 微软10亿美元投资AI公司助力云计算,研发通用人工智能
  5. 28条有关人工智能的名言,靠不靠谱你来看!
  6. 重新配对_郑思维和陈清晨当年配对也很强,为什么被拆开重新和黄雅琼配对
  7. 原码一位乘法器设计_对原码、反码和补码的加深理解
  8. python 写入网络视频文件很慢_OpenCV视频写入详解_Python,视频保存0kb问题
  9. 003_Spring使用Slf4j和logback日志
  10. html怎么加载xml文档,在html中解析xml文件(javascript 读取)