cglib invoke 和 invokeSuper 可用的组合
在深入字节码理解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 可用的组合的更多相关文章
- Cglib invoke以及invokeSuper的一点区别
简单记录下,解决的一个问题,Cglib的invoke和invokeSuper的区别: 简而言之,invoke方法调用的对象没有增强过,invokeSuper方法调用的对象已经是增强了的,所以会再走一遍 ...
- Cglib invoke为什么会死循环?
目录 Cglib invoke为什么会死循环? 动态代理子类的java文件 动态代理子类实例化过程 动态代理类调用过程 动态代理之MethodProxy.invokeSuper Cglib invok ...
- Cglib源码分析 invoke和invokeSuper的差别(转)
原文 https://blog.csdn.net/makecontral/article/details/79593732 Cglib的实例 本文重在源码的分析,Cglib的使用不再复述. //被代理 ...
- 【DP-动态代理】JDK&Cglib
需求:增强未知方法的代码 简单方案:继承或者聚合 继承,调用方法前后加增强逻辑 聚合 - 静态代理 持有被代理类对象 或者接口 可通过嵌套实现代理的组合 和 装饰器模式很像 高级方案 代理所有的类,不 ...
- java代理的深入浅出(二)-CGLIB
java代理的深入浅出(二)-CGLIB 1.基本原理 CGLIB的原理就是生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法.在子类中拦截所有父类方法的调用,拦截下来交给设置的Me ...
- Cglib及其基本使用
前言 最近一直在看Spring源码,其实我之前一直知道AOP的基本实现原理: 如果针对接口做代理默认使用的是JDK自带的Proxy+InvocationHandler 如果针对类做代理使用的是Cgli ...
- Cglib动态代理浅析
原文同步发表至个人博客[夜月归途] 原文链接:http://www.guitu18.com/se/java/2018-06-29/18.html 作者:夜月归途 出处:http://www.guitu ...
- CGLIB动态代理模式
概念: 第三方技术CGLIB动态代理和JDK代理不同的是,JDK代理需要提供接口,而CGLIB代理不需要: 它只需要一个非抽象类就能实现动态代理 例子: /** * 非抽象类 * @author Ad ...
- cglib的使用
前言 最近一直在看Spring源码,其实我之前一直知道AOP的基本实现原理: 如果针对接口做代理默认使用的是JDK自带的Proxy+InvocationHandler 如果针对类做代理使用的是Cgli ...
随机推荐
- Django框架之models和不依赖Qquery的ajax请求
一.models表字段 1)class表字段的创建 AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) ...
- python学习 day20 (3月27日)----(单继承多继承c3算法)
继承: 提高代码的重用性,减少了代码的冗余 这两个写法是一样的 Wa('青蛙').walk() #青蛙 can walk wa = Wa('青蛙') wa.walk() #青蛙 can walk 1. ...
- poj-3067(树状数组)
题目链接:传送门 题意:日本有东城m个城市,西城m个城市,东城与西城相互连线架桥,判断这些桥相交的次数. 思路:两个直线相交就是(x1-x2)*(y1-y2)<0,所以,对x,y进行排序,按照x ...
- mysql 配置MHA
在配置好GTID复制后,配置MHA的高可用. 1.准备3台机器 192.168.31.100 主库 192.168.31.101 从库 192.168.31.104 从库 MHA控制节点 2.设置SS ...
- Matlab编辑器背景修改
将下段代码如到C:\Users\Peng Chen\AppData\Roaming\MathWorks\MATLAB\R2016a\matlab.prf 先备份.prf,再替代之前的. #MATLAB ...
- linux系统配置参数修改
一.永久修改主机名修改/etc/sysconfig/network,在里面指定主机名称HOSTNAME=然后执行命令hostname 主机名这个时候可以注销一下系统,再重登录之后就行了. 或者修改/e ...
- s4-5 以太网帧
以太网所处的层次 IEEE 802.3/以太网MAC子层协议 IEEE802.3协议描述了运行在各种介质上1 Mb/s~10 Mb/s的1- 持续CSMA/CD协议的局域网标准. 很多人对以太 ...
- Linux未安装上传下载的插件,怎么进行文件的上传下载
首先连上服务: 然后Alt+p,打开SFTp窗口: 例如,我们今天要往tomcat的webappmu目录下上传一个文件: 先pwd,查看我们Linux上所处的目录:pwd 然后进入到tomcat的we ...
- Mybatis-Plus 实战完整学习笔记(五)------insert测试
一.更新操作探究(3.0.3版本) demo /** * 修改用户 * @throws SQLException */ @Test public void update() throws SQLExc ...
- IntelliJ IDEA 2017版 编译器使用学习笔记(十) (图文详尽版);IDE快捷键使用;IDE关联一切
关联一切 一.与spring关联 通过图标跳转相关联的类 设置关联:进入project structure ===>facets =>选加号,===>选spring,默认添 ...