深入字节码理解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);
}
												

最新文章

  1. 列属性:RowGUIDCol、Identity 和 not for replication
  2. linux iptables常用命令之配置生产环境iptables及优化
  3. MySQL学习笔记
  4. hdu5317 RGCDQ (质因子种数+预处理)
  5. Struts 2入门案例及登录
  6. 基础学习day04---数组的操作
  7. cURL 学习笔记与总结(4)使用 cURL 从 ftp 上下载文件与上传文件到 ftp
  8. 【转】JavaSript模块规范 - AMD规范与CMD规范介绍
  9. umbraco使用VS安装
  10. I题 - A+B for Input-Output Practice (VIII)
  11. numpy库:常用基本
  12. nyoj 47 江 河问题 【贪婪】
  13. 简单谈谈js中Promise的用法
  14. python学习(list增删改查、及常用方法)
  15. Linux Shell自动交互/人机交互的三种方法
  16. 微信公众号开发流程,jssdk的使用以及签名算法的实现
  17. 【hibernate】1、Hibernate的一个注解 @Transient
  18. c#.net基础
  19. Qt画笔实现折线图
  20. Redis全方位讲解--主从复制

热门文章

  1. lambda表达式和表达式树(深入理解c#)
  2. java学习第六周
  3. Centos7 yum install vim 出现“could not retrieve mirrorlist”
  4. Amount of Degrees(数位dp)
  5. C++STL set
  6. adb 相关命令 以及无法adb识别设备的解决方法
  7. MessageFormat.format()和String.format()
  8. 网络timeout区分
  9. 【Andorid开发框架学习】之Mina开发之Mina简介
  10. CALayer-CAShapeLayer/CAGradientLayer