java JDK 動態代理(如何使用,以及工作原理解析)

JDK 動態代理如何使用

1:實現 InvocationHandler 接口
2:有一個自己定義的接口,名稱爲 InterFace。有一個實現InterFace接口的實現類。
3:使用 Proxy 中的 newProxyInstance 方法創建代理類。

具體的實現是請看下面的代碼

被代理接口
package com.javaproxy.test;

public interface InterFace {

    public String interFaceMethod(String str);

}

被代理接口實現類
package com.javaproxy.test;

public class InterFaceImpl implements InterFace{

    @Override
    public String interFaceMethod(String str) {
        return str + "+lp";
    }

}

InvocationHandler接口實現類
package com.javaproxy.test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class InvocationHandlerImpl implements InvocationHandler {

    //要代理的原始對象
    private Object obj;

    public InvocationHandlerImpl(Object obj) {
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("執行被代理方法前,需要做的處理doBefore");
        System.out.println("執行被代理方法 ing");
        Object result = method.invoke(obj, args);
        System.out.println("執行被代理方法後,需要做的處理doAfter");
        return result;
    }

}

測試類
package com.javaproxy.test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class TestJavaProxy {

    public static void main(String[] args) {
        InterFace impl = new InterFaceImpl();
        InvocationHandler handler = new InvocationHandlerImpl(impl);
        Object proxyObj= Proxy.newProxyInstance(impl.getClass().getClassLoader(), impl.getClass().getInterfaces(), handler);
        InterFace inter = (InterFace) proxyObj;
        inter.interFaceMethod("lp");
    }

}

運行測試類,結果
執行被代理方法前,需要做的處理doBefore
執行被代理方法 ing
執行被代理方法後,需要做的處理doAfter

JDK動態代理原理解析

JDK提供了sun.misc.ProxyGenerator.generateProxyClass(String proxyName,class[] interfaces) 底層方法來產生動態代理類的字節碼:
下面定義了一個工具類,用來將生成的動態代理類保存到硬盤中:

package com.javaproxy.test;

import java.io.FileOutputStream;
import java.io.IOException;
import sun.misc.ProxyGenerator;

public class ProxyUtils {

    /*
     * 將根據類信息 動態生成的二進制字節碼保存到硬盤中,
     * 默認保存到 D 盤根目錄下
     * clazz 需要生成動態代理類的類
     * proxyName : 爲動態生成的代理類的名稱
     */
    public static void generateClassFile(Class<?> clazz, String proxyName) {
        // 根據類信息和提供的代理類名稱,生成字節碼
        byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
        // String paths = clazz.getResource(".").getPath();
        String paths = "D:/";
        FileOutputStream out = null;

        try {
            // 保留到硬盤中
            out = new FileOutputStream(paths + proxyName + ".class");
            out.write(classFile);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

在測試類TestJavaProxy 中的main方法中的 Proxy.newProxyInstance代碼下面添加代碼 ProxyUtils.generateClassFile(proxyObj.getClass(), "ProxyObj");
這樣就可以在,D盤的根目錄下,找到 ProxyObj.class 文件,使用jd-gui 反編譯工具打開。反編譯後,代碼如下。

import com.javaproxy.test.InterFace;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class ProxyObj extends Proxy
  implements InterFace
{
  private static Method m1;
  private static Method m0;
  private static Method m3;
  private static Method m2;

  public ProxyObj(InvocationHandler paramInvocationHandler)
    throws 
  {
    super(paramInvocationHandler);
  }

  public final boolean equals(Object paramObject)
    throws 
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final int hashCode()
    throws 
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final String interFaceMethod(String paramString)
    throws 
  {
    try
    {
      return (String)this.h.invoke(this, m3, new Object[] { paramString });
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final String toString()
    throws 
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  static
  {
    try
    {
      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]);
      m3 = Class.forName("com.javaproxy.test.InterFace").getMethod("interFaceMethod", new Class[] { Class.forName("java.lang.String") });
      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());
    }
  }
}

可以看到 通過 java.lang.reflect.Proxy 的方法 newProxyInstance 獲取的代理類(ProxyObj),實現了,自己定義的 InterFace接口。所以在測試類裏面,可以將 獲取的代理類(ProxyObj)強制轉換爲InterFace對象類型。

再看 獲取的代理類(ProxyObj),是如何調用被代理對象的,以及如何調用InvocationHandler接口實現類的。

代理類調用過程
1:獲取的代理類強制轉換爲InterFace對象類型,調用 interFaceMethod 方法。
實際調用的方法 是 類ProxyObj 裏面的interFaceMethod方法。
2:那麼接着看,類ProxyObj 裏面的interFaceMethod方法,方法內的代碼是
try
{
return (String)this.h.invoke(this, m3, new Object[] { paramString });
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}

方法內,調用了代理類自己的屬性 h(從java.lang.reflect.Proxy 繼承過來的) 即咱們自己的InvocationHandler 接口的實現類InvocationHandlerImpl,然後調用, h 的 invoke方法。看看 invoke方法的參數,第一個參數傳入進入的是代理對象自己,第二參數是靜態代碼初始化的Method對象
m3 = Class.forName("com.javaproxy.test.InterFace").getMethod("interFaceMethod", new Class[] { Class.forName("java.lang.String") });
第三個參數是,調用代理類對象中的方法是傳遞進來的參數。

講到這裏大家應該可以理解JDK的動態代理是怎麼實現的了。

這個再貼一篇文章的地址,點擊打開

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章