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的動態代理是怎麼實現的了。