討論和學習JDK API 實現動態代理,源碼分析
前置知識
- 瞭解類是由屬性和方法構成
- 瞭解Java可以動態定義類信息
- 瞭解反射
基本概念:
動態代理
:爲實現某個接口的原始類(被代理類),在運行時動態生成代理對象
代理
:在被代理之前的,代理被代理的
被代理
:需要代理協助的對象
邏輯推理/猜想
1.代理
和被代理
之間要有關聯
2.對外展示的功能是一樣。
3.再想想具體的Java實現
通過什麼手段能爲一個類或者接口動態生成代理 ?
- 對象是由類生成,所以先需要生成類,在生成對象,
類
是由屬性
和方法
構成,這裏重點關注方法,那我們我們生成的類,應該具備哪些方法呢? 因爲代理和被代理對外是一致的,所被代理
有哪些方法,那代理
也就有哪些方法,所以我們就可以生成類,接着就可以生成代理對象。
代碼演示
- 定義代理和被代理類都需要實現的
接口
public interface ITest {
void test();
}
被代理實現接口
/**
* 被代理
* @Author: malone
* @Date 2020/6/26 23:08
*/
public class Represented implements ITest {
@Override
public void test() {
System.out.println("Represented method invocation");
}
}
- 根據JDK創建代理對象的方法需要,實現
InvocationHandler
接口
/**
* @Author: malone
* @Date 2020/6/26 23:09
*/
public class DynamicInvocationHandler implements InvocationHandler {
// 被代理對象
private Object object;
public DynamicInvocationHandler(Object object){
this.object = object;
}
// 方法調用攔截
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invoke proxy method");
method.invoke(object,args); // 調用被代理方法,通過反射方法
return null;
}
}
- 調用
public static Object newProxyInstance()
創建代理對象
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
loader
:當前被代理對象使用的類加載器
interfaces
:需要實現接口數組
h
: 第2步實現了InvocationHandler
接口的對象
下面是動態代理DynamicProxy
的測試,通過newProxyInstance
方法,創建代理對象proxy
,在代理
對象上調用和被代理
對象相同的方法,我們看到,代理對象和被代理對象的信息都輸出了。
/**
* @Author: malone
* @Date 2020/6/26 23:11
*/
public class DynamicProxyTest {
public static void main(String[] args) {
String property = "sun.misc.ProxyGenerator.saveGeneratedFiles";
System.getProperties().setProperty(property ,"true");
// 以上兩句話用於保存,JDK動態產生的代理類Proxy0
ITest represented = new Represented(); // 被代理實例
ITest proxy = (ITest)Proxy.newProxyInstance(represented.getClass().getClassLoader(),
represented.getClass().getInterfaces(),new DynamicInvocationHandler(represented));
proxy.test(); // 通過代理調用方法
}
}
下面是輸出
invoke proxy method
Represented method invocation
源碼
String property = "sun.misc.ProxyGenerator.saveGeneratedFiles";
System.getProperties().setProperty(property ,"true");
上面兩個代碼將保存生成的代理類$Proxy0
到本地.我,我們打開看看。
生成類所在位置
public final class $Proxy0 extends Proxy implements ITest {
生成的類繼承了Proxy類,實現了ITest類,這也就保證了和被代理一致的行爲。至於繼承Proxy類是爲了調用InvocationHandler中的Invoke方法,也就是我們實現代理邏輯的方法。如下所示,我們主要看ITest中定義的方法test在生成類中的實現。
public final void test() throws {
try {
// 調用父類Proxy中的InvocationHandler的invoke方法
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
總結
- 邏輯中涉及
代理
對象和被代理
對象兩個角色 - 實現中,涉及接口定義、代理的定義(
InvocationHandler
接口實現)、代理的創建Proxy.newProxyInstance
方法的調用 - 涉及
反射
知識:被代理類的方法調用