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 ...
随机推荐
- 浅谈 [Ljava.lang.Object 异常
http://blog.csdn.net/goodleiwei/article/details/7059567 主要原因:取出的是对象的数组,需要遍历单个的对象并获取想用的属性值
- MySQL LOCK TABLES 与UNLOCK TABLES
http://blog.csdn.net/zyz511919766/article/details/16342003 1语法 LOCK TABLES tbl_name[[AS] alias] lock ...
- org.jsoup.HttpStatusException: HTTP error fetching URL. Status=403
爬取网站的时候 conn = Jsoup.connect(url).timeout(5000).get();直接用get方法,有些网站可以正常爬取. 但是有些网站报403错误,403是一种在网站访问的 ...
- 微信小程序设置全局字体
微信小程序设置全局css,需要在app.wxss文件中设置page的样式 page { font-family:"PingFangSC-Thin"; font-size:32rpx ...
- s4-7 生成树协议
Spanning Tree :为了可靠,采用冗余结构:但是透明网桥 会产生无休止循环的问题 冗余交换拓扑可能带来的问题 广播风暴 多帧传送 MAC地址库不稳定 生成树协议 STP:sp ...
- PHP continue break 区别 用法
<?php //continue 跳过当前循环,进行下一个 //break 终止当前循环 $db=new PDO("mysql:host=localhost;dbname=root&q ...
- HttpFilter
import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import ja ...
- android:padding和android:margin的区别[转]
本文综合了:http://zhujiao.iteye.com/blog/1856980 和 http://blog.csdn.net/maikol/article/details/6048647 两篇 ...
- noip第27课作业
1. 繁忙的都市 [问题描述] 城市C是一个非常繁忙的大都市,城市中的道路十分的拥挤,于是市长决定对其中的道路进行改造.城市C的道路是这样分布的:城市中有n个交叉路口,有些交叉路口之间有道路相连,两个 ...
- h5canvas绘制loading页面
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...