zoukankan      html  css  js  c++  java
  • Jdk动态代理和CGLIB动态代理大比拼

    前言:

       这2种动态代理算是老生常谈的吧,面试还是会经常问到的,下面做下分析:

    jdk动态代理:

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class JdkHanler implements InvocationHandler {
        
        private Object target;
        
        public Object invoke(Object proxy, Method method, Object[] arg) throws Throwable {
            System.out.println("before");
            Object o=method.invoke(target, arg);
            System.out.println("after");
            return o;
        }
        public JdkHanler(Object target) {
            super();
            this.target = target;
        }
        public Object getInstance(){
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
                    target.getClass().getInterfaces(), this);
        }
    }
    View Code

    cglib动态代理:

    import java.lang.reflect.Method;
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    public class HelloWorldInterceptor implements MethodInterceptor {
    
        private Object target;
        
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("before");
            Object r=proxy.invokeSuper(obj, args);
            System.out.println("after");
            return r;
        }
        public HelloWorldInterceptor(Object target) {
            super();
            this.target = target;
        }
        public Object getInstance(){
            Enhancer enhancer=new Enhancer();
            enhancer.setSuperclass(target.getClass());
            enhancer.setCallback(this);
            return enhancer.create();
        }
    }
    View Code

    测试类:

    public class AllTest {
        
        public static final String output="D:/SpringWorkSpace/";
        //cglib生成代理类字节码文件
        static{
            System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, output);
        }
        
        @Test
        public void proxyTest(){
            HelloWorldInterceptor interceptor=new HelloWorldInterceptor(new HelloWorldImpl());
            HelloWorld h=(HelloWorld) interceptor.getInstance();
            h.sayHello();
        }
        //@Test
        public void jdkproxyTest() throws IOException{
            JdkHanler hanler=new JdkHanler(new HelloWorldImpl());
            HelloWorld h=(HelloWorld) hanler.getInstance();
            h.sayHello();
            jdkToFile(h);
        }
    //jdk代理类字节码文件
        public static void jdkToFile(HelloWorld obj) throws IOException {
            Class clazz = obj.getClass();
            String className = clazz.getName();
            byte[] classFile = ProxyGenerator.generateProxyClass(className, HelloWorldImpl.class.getInterfaces());
            FileOutputStream fos = new FileOutputStream(output+"proxy.class");
            fos.write(classFile);
        }
    }
    View Code

    利用jd-gui工具反编译字节码文件:

    生成的jdk代理类:

    public final class $Proxy4 extends Proxy
      implements HelloWorld
    {
      private static Method m3;
      private static Method m1;
      private static Method m0;
      private static Method m2;
    
      public $Proxy4(InvocationHandler paramInvocationHandler)
        throws 
      {
        super(paramInvocationHandler);
      }
      //调用sayHello方法
      public final String sayHello()
        throws 
      {
        try
        {
         //调用JdkHanler的invoke方法
          return (String)this.h.invoke(this, m3, null);
        }
        catch (Error|RuntimeException localError)
        {
          throw localError;
        }
        catch (Throwable localThrowable)
        {
          throw new UndeclaredThrowableException(localThrowable);
        }
      }
    
      static
      {
        try
        {
          m3 = Class.forName("com.selrain.DynamicProxy.HelloWorld").getMethod("sayHello", new Class[0]);
          m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
          m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
          m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
          return;
        }
        catch (NoSuchMethodException localNoSuchMethodException)
        {
          throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
        }
        catch (ClassNotFoundException localClassNotFoundException)
        {
          throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
        }
      }
    View Code

    生成的cglib代理类:

    public class HelloWorld$$EnhancerByCGLIB$$d87b5f2a extends HelloWorld
      implements Factory
    {
      private boolean CGLIB$BOUND;
      public static Object CGLIB$FACTORY_DATA;
      private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
      private static final Callback[] CGLIB$STATIC_CALLBACKS;
      private MethodInterceptor CGLIB$CALLBACK_0;
      private static Object CGLIB$CALLBACK_FILTER;
      private static final Method CGLIB$sayHello$0$Method;
      private static final MethodProxy CGLIB$sayHello$0$Proxy;
      private static final Object[] CGLIB$emptyArgs;
      private static final Method CGLIB$hashCode$1$Method;
      private static final MethodProxy CGLIB$hashCode$1$Proxy;
      private static final Method CGLIB$clone$2$Method;
      private static final MethodProxy CGLIB$clone$2$Proxy;
      private static final Method CGLIB$equals$3$Method;
      private static final MethodProxy CGLIB$equals$3$Proxy;
      private static final Method CGLIB$toString$4$Method;
      private static final MethodProxy CGLIB$toString$4$Proxy;
    
      static void CGLIB$STATICHOOK1()
      {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class localClass1 = Class.forName("com.selrain.DynamicProxy.HelloWorld$$EnhancerByCGLIB$$d87b5f2a");
        Class localClass2;
        Method[] tmp50_47 = ReflectUtils.findMethods(new String[] { "sayHello", "()Ljava/lang/String;" }, (localClass2 = Class.forName("com.selrain.DynamicProxy.HelloWorld")).getDeclaredMethods());
        CGLIB$sayHello$0$Method = tmp50_47[0];
        CGLIB$sayHello$0$Proxy = MethodProxy.create(localClass2, localClass1, "()Ljava/lang/String;", "sayHello", "CGLIB$sayHello$0");
        tmp50_47;
        Method[] tmp131_128 = ReflectUtils.findMethods(new String[] { "hashCode", "()I", "clone", "()Ljava/lang/Object;", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;" }, (localClass2 = Class.forName("java.lang.Object")).getDeclaredMethods());
        CGLIB$hashCode$1$Method = tmp131_128[0];
        CGLIB$hashCode$1$Proxy = MethodProxy.create(localClass2, localClass1, "()I", "hashCode", "CGLIB$hashCode$1");
        Method[] tmp151_131 = tmp131_128;
        CGLIB$clone$2$Method = tmp151_131[1];
        CGLIB$clone$2$Proxy = MethodProxy.create(localClass2, localClass1, "()Ljava/lang/Object;", "clone", "CGLIB$clone$2");
        Method[] tmp171_151 = tmp151_131;
        CGLIB$equals$3$Method = tmp171_151[2];
        CGLIB$equals$3$Proxy = MethodProxy.create(localClass2, localClass1, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$3");
        Method[] tmp191_171 = tmp171_151;
        CGLIB$toString$4$Method = tmp191_171[3];
        CGLIB$toString$4$Proxy = MethodProxy.create(localClass2, localClass1, "()Ljava/lang/String;", "toString", "CGLIB$toString$4");
        tmp191_171;
      }
    
      final String CGLIB$sayHello$0()
      {
        return super.sayHello();
      }
     //调用sayHello方法
      public final String sayHello()
      {
        MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
        if (tmp4_1 == null)
        {
          tmp4_1;
          CGLIB$BIND_CALLBACKS(this);
        }
        MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
        if (tmp17_14 != null)
    //HelloWorldInterceptor 的intercept 方法
          return (String)tmp17_14.intercept(this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
        return super.sayHello();
      }
    
      final int CGLIB$hashCode$1()
      {
        return super.hashCode();
      }
    
      public final int hashCode()
      {
        MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
        if (tmp4_1 == null)
        {
          tmp4_1;
          CGLIB$BIND_CALLBACKS(this);
        }
        MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
        if (tmp17_14 != null)
        {
          Object tmp36_31 = tmp17_14.intercept(this, CGLIB$hashCode$1$Method, CGLIB$emptyArgs, CGLIB$hashCode$1$Proxy);
          tmp36_31;
          return tmp36_31 == null ? 0 : ((Number)tmp36_31).intValue();
        }
        return super.hashCode();
      }
    
      final Object CGLIB$clone$2()
        throws CloneNotSupportedException
      {
        return super.clone();
      }
    
      protected final Object clone()
        throws CloneNotSupportedException
      {
        MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
        if (tmp4_1 == null)
        {
          tmp4_1;
          CGLIB$BIND_CALLBACKS(this);
        }
        MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
        if (tmp17_14 != null)
          return tmp17_14.intercept(this, CGLIB$clone$2$Method, CGLIB$emptyArgs, CGLIB$clone$2$Proxy);
        return super.clone();
      }
    
      final boolean CGLIB$equals$3(Object paramObject)
      {
        return super.equals(paramObject);
      }
    
      public final boolean equals(Object paramObject)
      {
        MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
        if (tmp4_1 == null)
        {
          tmp4_1;
          CGLIB$BIND_CALLBACKS(this);
        }
        MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
        if (tmp17_14 != null)
        {
          Object tmp41_36 = tmp17_14.intercept(this, CGLIB$equals$3$Method, new Object[] { paramObject }, CGLIB$equals$3$Proxy);
          tmp41_36;
          return tmp41_36 == null ? false : ((Boolean)tmp41_36).booleanValue();
        }
        return super.equals(paramObject);
      }
    
      final String CGLIB$toString$4()
      {
        return super.toString();
      }
    
      public final String toString()
      {
        MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
        if (tmp4_1 == null)
        {
          tmp4_1;
          CGLIB$BIND_CALLBACKS(this);
        }
        MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
        if (tmp17_14 != null)
          return (String)tmp17_14.intercept(this, CGLIB$toString$4$Method, CGLIB$emptyArgs, CGLIB$toString$4$Proxy);
        return super.toString();
      }
    
      public static MethodProxy CGLIB$findMethodProxy(Signature paramSignature)
      {
        String tmp4_1 = paramSignature.toString();
        switch (tmp4_1.hashCode())
        {
        case -508378822:
          if (tmp4_1.equals("clone()Ljava/lang/Object;"))
            return CGLIB$clone$2$Proxy;
          break;
        case 1459740658:
        case 1826985398:
        case 1913648695:
        case 1984935277:
        }
      }
    
      public HelloWorld$$EnhancerByCGLIB$$d87b5f2a()
      {
        CGLIB$BIND_CALLBACKS(this);
      }
    
      public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] paramArrayOfCallback)
      {
        CGLIB$THREAD_CALLBACKS.set(paramArrayOfCallback);
      }
    
      public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] paramArrayOfCallback)
      {
        CGLIB$STATIC_CALLBACKS = paramArrayOfCallback;
      }
    
      private static final void CGLIB$BIND_CALLBACKS(Object paramObject)
      {
        // Byte code:
        //   0: aload_0
        //   1: checkcast 2    com/selrain/DynamicProxy/HelloWorld$$EnhancerByCGLIB$$d87b5f2a
        //   4: astore_1
        //   5: aload_1
        //   6: getfield 186    com/selrain/DynamicProxy/HelloWorld$$EnhancerByCGLIB$$d87b5f2a:CGLIB$BOUND    Z
        //   9: ifne +43 -> 52
        //   12: aload_1
        //   13: iconst_1
        //   14: putfield 186    com/selrain/DynamicProxy/HelloWorld$$EnhancerByCGLIB$$d87b5f2a:CGLIB$BOUND    Z
        //   17: getstatic 27    com/selrain/DynamicProxy/HelloWorld$$EnhancerByCGLIB$$d87b5f2a:CGLIB$THREAD_CALLBACKS    Ljava/lang/ThreadLocal;
        //   20: invokevirtual 189    java/lang/ThreadLocal:get    ()Ljava/lang/Object;
        //   23: dup
        //   24: ifnonnull +15 -> 39
        //   27: pop
        //   28: getstatic 184    com/selrain/DynamicProxy/HelloWorld$$EnhancerByCGLIB$$d87b5f2a:CGLIB$STATIC_CALLBACKS    [Lnet/sf/cglib/proxy/Callback;
        //   31: dup
        //   32: ifnonnull +7 -> 39
        //   35: pop
        //   36: goto +16 -> 52
        //   39: checkcast 190    [Lnet/sf/cglib/proxy/Callback;
        //   42: aload_1
        //   43: swap
        //   44: iconst_0
        //   45: aaload
        //   46: checkcast 52    net/sf/cglib/proxy/MethodInterceptor
        //   49: putfield 40    com/selrain/DynamicProxy/HelloWorld$$EnhancerByCGLIB$$d87b5f2a:CGLIB$CALLBACK_0    Lnet/sf/cglib/proxy/MethodInterceptor;
        //   52: return
      }
    
      public Object newInstance(Callback[] paramArrayOfCallback)
      {
        CGLIB$SET_THREAD_CALLBACKS(paramArrayOfCallback);
        CGLIB$SET_THREAD_CALLBACKS(null);
        return new d87b5f2a();
      }
    
      public Object newInstance(Callback paramCallback)
      {
        CGLIB$SET_THREAD_CALLBACKS(new Callback[] { paramCallback });
        CGLIB$SET_THREAD_CALLBACKS(null);
        return new d87b5f2a();
      }
    
      public Object newInstance(Class[] paramArrayOfClass, Object[] paramArrayOfObject, Callback[] paramArrayOfCallback)
      {
        CGLIB$SET_THREAD_CALLBACKS(paramArrayOfCallback);
        Class[] tmp9_8 = paramArrayOfClass;
        switch (tmp9_8.length)
        {
        case 0:
          tmp9_8;
          break;
        default:
          new d87b5f2a();
          throw new IllegalArgumentException("Constructor not found");
        }
        CGLIB$SET_THREAD_CALLBACKS(null);
      }
    
      public Callback getCallback(int paramInt)
      {
        CGLIB$BIND_CALLBACKS(this);
        switch (paramInt)
        {
        case 0:
          break;
        }
        return null;
      }
    
      public void setCallback(int paramInt, Callback paramCallback)
      {
        switch (paramInt)
        {
        case 0:
          this.CGLIB$CALLBACK_0 = ((MethodInterceptor)paramCallback);
          break;
        }
      }
    
      public Callback[] getCallbacks()
      {
        CGLIB$BIND_CALLBACKS(this);
        return new Callback[] { this.CGLIB$CALLBACK_0 };
      }
    
      public void setCallbacks(Callback[] paramArrayOfCallback)
      {
        this.CGLIB$CALLBACK_0 = ((MethodInterceptor)paramArrayOfCallback[0]);
      }
    
      static
      {
        CGLIB$STATICHOOK1();
      }
    }
    View Code

    MethodProxy 的invokeSuper方法:

    public Object invokeSuper(Object obj, Object[] args) throws Throwable {
            try {
                init();
                FastClassInfo fci = fastClassInfo;
    //调用代理类的CGLIB$sayHello$0方法
                return fci.f2.invoke(fci.i2, obj, args);
            } catch (InvocationTargetException e) {
                throw e.getTargetException();
            }
        }
    //生成fastClass类:其中f1代表target,(其type属性为target),f2代表生成的代理类;i1和i2分别代表方法sayHello和CGLIB$sayHello$0方法对应的索引位置
    private void init()
        {
            if (fastClassInfo == null)
            {
                synchronized (initLock)
                {
                    if (fastClassInfo == null)
                    {
                        CreateInfo ci = createInfo;
    
                        FastClassInfo fci = new FastClassInfo();
                        fci.f1 = helper(ci, ci.c1);
                        fci.f2 = helper(ci, ci.c2);
                        fci.i1 = fci.f1.getIndex(sig1);
                        fci.i2 = fci.f2.getIndex(sig2);
                        fastClassInfo = fci;
                        createInfo = null;
                    }
                }
            }
        }
    View Code

    代理类的CGLIB$sayHello$0方法:

    final String CGLIB$sayHello$0()
      {
    //最终调用target的sayHello方法
        return super.sayHello();
      }
    View Code

    区别:

      1、jdk动态代理生成的代理类和委托类实现了相同的接口

      2、jdk动态代理利用了Java的反射机制,cglib动态代理利用了索引的方式直接调用委托类的方法,效率更高

    参考:

       1、占小狼的博客-说说cglib动态代理

       2、饿了么物流技术-动态代理的实现与案例

         

  • 相关阅读:
    力扣238.除自身以外数组的乘积 & 剑指offer 51.构建乘积数组
    网易的Airtest
    ZOOKEEPER
    Apache和Nginx负载均衡集群及测试分析
    mysql——创建索引、修改索引、删除索引的命令语句
    sql-索引的作用
    ADB连接手机的两种方式(usb数据线连接和wifi连接)
    adb shell dumpsys 命令
    count(*) 和 count(1)和count(列名)区别
    博客园页面设置
  • 原文地址:https://www.cnblogs.com/Non-Tecnology/p/6791655.html
Copyright © 2011-2022 走看看