cglib动态代理实现原理

来源:互联网 发布:大数据征信查询入口app 编辑:程序博客网 时间:2024/04/30 14:58

cglib是一个字节码操纵库,底层基于ASM框架。虽然JDK同样提供了动态代理功能,但是必须将需要代理的方法写在接口中,由主体类继承,很不灵活,而且性能不如cglib。下面是一个使用cglib动态代理的例子。

主体类:

public class MyClass {public void print() {      System.out.println("I'm in MyClass.print!");  }  }

代理类:

public class Main { public static void main(String[] args) {System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, System.getProperty("user.dir") + "/bin");Enhancer enhancer = new Enhancer();enhancer.setSuperclass(MyClass.class);enhancer.setCallback(new MethodInterceptorImpl());MyClass my = (MyClass) enhancer.create();my.print();}    private static class MethodInterceptorImpl implements MethodInterceptor {    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {// log somethingSystem.out.println(method + " intercepted!");proxy.invokeSuper(obj, args);return null;}}}

实现原理:
1.操纵字节码,生成Myclass的子类。将MyClass的子类的字节码反编译之后,看起来会接近这个等价类:
class MyClass$$EnhancerByCGLIB extends MyClass{private MethodInterceptor methodInterceptor;public void print() throws Throwable {Class localClass = Class.forName("cgproxy.MyClass$$EnhancerByCGLIB");    ClassLoader classLoader = localClass.getClassLoader();    Method method = Class.forName("cgproxy.MyClass").getDeclaredMethod("print", new Class[0]);    MethodProxy methodProxy = MethodProxy.create(classLoader, method.getDeclaringClass(), localClass, "()V", "print", "CGLIB$print");methodInterceptor.intercept(this, method, null, methodProxy);}public void CGLIB$print() {super.print();}}
需要注意的是,继承自Object的方法都会按相同的方式生成字节码,wait,notify方法除外,因此MyClass.toString()也会被代理。
这是直接由字节码反编译的结果,可以忽略
public class MyClass$$EnhancerByCGLIB$$1e2eda10 extends MyClass  implements Factory {static void CGLIB$STATICHOOK1() {    CGLIB$THREAD_CALLBACKS = new ThreadLocal();    Class localClass;    CGLIB$emptyArgs = new Object[0];    ClassLoader tmp27_17 = (localClass = Class.forName("cgproxy.MyClass$$EnhancerByCGLIB$$1e2eda10")).getClassLoader();    CGLIB$print$0$0$Proxy = MethodProxy.create(tmp27_17, (1e2eda10.CGLIB$print$0$0$Method = Class.forName("cgproxy.MyClass").getDeclaredMethod("print", new Class[0])).getDeclaringClass(), localClass, "()V", "print", "CGLIB$print$0$0");    return;}final void CGLIB$print$0$0() {super.print();}public final void print() {MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;if (tmp4_1 == null){tmp4_1;CGLIB$BIND_CALLBACKS(this);}if (this.CGLIB$CALLBACK_0 != null)return;  super.print();}}
2.执行代码,enhancer.create返回的是MyClass$$EnhancerByCGLIB类的实例,my.print()实际调用的是MyClass$$EnhancerByCGLIB.print(),然后会被MethodInterceptor代理类拦截
3.完成前置代理
4.调用主体类的print()方法:MethodProxy.invokeSuper(MyClass$$EnhancerByCGLIB, Object[]), 这是MethodProxy的相关代码
public class MethodProxy {private FastClass f2;private int i2;   public Object invokeSuper(Object obj, Object[] args) throws Throwable {         try {             return f2.invoke(i2, obj, args);        } catch (InvocationTargetException e) {             throw e.getTargetException();        }     }}
FastClass也是操纵字节码动态生成的类,invoke()会根据事先建立的int值与方法之间的映射,通过int索引访问方法,字节码如下(可能是JD-GUI支持的jdk版本太低了,这一段不能反编译成Java代码)
  public Object invoke(int paramInt, Object paramObject, Object[] paramArrayOfObject)
    throws InvocationTargetException  {    // Byte code:    //   0: aload_2//load paramObject到oprand stack    //   1: checkcast 152cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10//类型检查    //   4: iload_1//load paramInt索引到opran stack    //   5: tableswitchdefault:+387 -> 392, 0:+123->128, 1:+138->143, 2:+142->147, 3:+154->159, 4:+176->181, 5:+186->191, 6:+196->201//跳转    //   129: iconst_0    //   130: aaload    //   131: invokevirtual 153cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:equals(Ljava/lang/Object;)Z    //   134: new 155java/lang/Boolean    //   137: dup_x1    //   138: swap    //   139: invokespecial 158java/lang/Boolean:<init>(Z)V    //   142: areturn    //   143: invokevirtual 159cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:toString()Ljava/lang/String;    //   146: areturn    //   147: invokevirtual 160cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:hashCode()I    //   150: new 162java/lang/Integer    //   153: dup_x1    //   154: swap    //   155: invokespecial 165java/lang/Integer:<init>(I)V    //   158: areturn    //   159: aload_3    //   160: iconst_0    //   161: aaload    //   162: checkcast 167[Ljava/lang/Class;    //   165: aload_3    //   166: iconst_1    //   167: aaload    //   168: checkcast 169[Ljava/lang/Object;    //   171: aload_3    //   172: iconst_2    //   173: aaload    //   174: checkcast 171[Lnet/sf/cglib/proxy/Callback;    //   177: invokevirtual 174cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:newInstance([Ljava/lang/Class;[Ljava/lang/Object;[Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;    //   180: areturn    //   181: aload_3    //   182: iconst_0    //   183: aaload    //   184: checkcast 176net/sf/cglib/proxy/Callback    //   187: invokevirtual 179cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:newInstance(Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;    //   190: areturn    //   191: aload_3    //   192: iconst_0    //   193: aaload    //   194: checkcast 171[Lnet/sf/cglib/proxy/Callback;    //   197: invokevirtual 182cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:newInstance([Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;    //   200: areturn    //   201: invokevirtual 185cgproxy/MyClass$$EnhancerByCGLIB$$1e2eda10:print()V//paramObject.print()    //   204: aconst_null//将null压入oprand stack    //   205: areturn//return}

5.方法返回,如果有后置增强的话,进行后置增强

Java字节代码增强(ASM)

JDK动态代理示例

html学得好,博客写到老,各种奇怪的字符都得手动删,囧

0 0
原创粉丝点击