更新時間:2022-10-20 10:10:27 來源:動力節點 瀏覽1285次
Java 動態代理類是原始類之上的一種“附加組件”,它允許Java 開發人員根據需要更改原始類的行為。假設,如果您將一個類用作現成JAR 庫的一部分,并且您不能簡單地重寫其源代碼,但您還需要更改該類的行為方式。
例如,您不知道可以在您的對象上調用此類的哪個方法,但您想輸出一個重要的“確認”消息。Java 動態代理是這個問題的理想解決方案。
在本文中,我們將了解有關 Java 動態代理的所有信息。什么是 Java 動態代理?他們是如何工作的?以及何時應該在您的 Java 代碼中理想地使用它。
Java 動態代理是 Java 代理設計模式的一部分。當程序需要擴展或修改現有類的某些功能時,它允許創建代理對象。在這種情況下,將實例化代理對象而不是原始對象。通常,代理對象具有與原始對象相同的方法,并且在 Java 代理類中擴展了原始類。Java 動態代理模式具有原始對象的句柄,并且也可以調用原始類方法。
因此,代理類可以以非常方便的方式實現很多不同的東西,這樣的事情很少有例子包括:
可以將日志記錄方法擴展到原始類以記錄方法何時啟動和停止。
可以使用 Java 動態代理對參數執行額外的檢查。
代理類也可用于在最終確定之前模擬原始類的行為,以檢查它是否按預期執行。
如果不修改類的原始代碼,就無法完成上述應用,這使得它們成為 Java 動態代理的理想應用。
在這樣的應用程序中,代理類不直接在原始類對象上實現功能。遵循單一職責原則,代理類只創建一個代理,并在處理程序中修改實際行為。當調用代理對象而不是原始對象時,Java 動態代理將決定是否必須調用原始方法或處理程序。處理程序可以執行其擴展任務,也可以調用原始方法來執行原始任務。
它是 Java 編程語言中一個相對高級的主題,因為它需要一些廣泛的 Java 知識。計劃使用 Java 動態代理的開發人員必須了解反射類的使用或字節碼操作或如何編譯動態生成的 Java 代碼。要創建字節碼,首先應該學習如何使用 cglib 或 bytebuddy 或內置的 Java 編譯器。
InvocationHandler 是一個特殊的接口,它允許我們攔截對對象的任何方法調用并添加我們需要的附加行為。我們首先需要通過創建一個實現此接口的類來創建我們的攔截器。它只包含一個方法:invoke(),其中原始對象作為參數傳遞,被代理。
當我們考慮代理類和它們調用的處理程序時,就會明白為什么責任分離在這里非常重要。代理類總是在運行時生成,但代理類調用的處理程序可以用源代碼編碼,并且可以在編譯時與整個程序的代碼一起編譯。
代理類及其實例是使用 java.lang.reflect.Proxy 類的靜態方法創建的。它是 JDK 的一部分,可以創建代理類或直接創建它的實例。Java 內置代理的使用相對容易一些。您需要做的就是實現一個 java.lang.InvocationHandler,以便代理對象稍后可以調用它。在此之后,調用來自 Invocation Handler 的 invoke() 方法。
另一個方法,Proxy.getProxyClass 方法返回一個代理類的 java.lang.Class 對象,給定一個類加載器和一個接口數組。
根據動態代理類 Java 文檔,必須傳遞給 Proxy.getProxyClass 的參數有一些限制:
interfaces 數組中的所有 Class 對象都必須表示接口,而不是類或原始類型。
interfaces 數組中的兩個元素不能引用相同的 Class 對象。
所有接口類型必須通過指定的類加載器按名稱可見。
所有非公共接口必須在同一個包中;否則,代理類將不可能實現所有接口,無論它定義在什么包中。
對于具有相同簽名的指定接口的任意數量的成員方法:
如果任何方法的返回類型是 void 或原始類型,則所有方法都必須具有相同的返回類型。
如果不是,則其中一個方法必須具有可以分配給所有方法的所有返回類型的返回類型。
生成的代理類不得超過虛擬機對類施加的任何限制。
下面的代碼演示了在代碼中使用 Java 動態代理的所有討論點:
包代理;
導入java.lang.reflect.InvocationHandler;
導入java.lang.reflect.InvocationTargetException;
導入java.lang.reflect.Method;
導入java.lang.reflect.Proxy;
公共類 ProxyDemo {
接口如果{
void originalMethod(String str);
}
靜態類原始實現If {
public void originalMethod(String str) {
System.out.println(str);
}
}
靜態類Handler實現InvocationHandler {
private final If original;
public Handler(如果是原始的) {
this.original = 原創;
}
public Object invoke(Object proxy, Method method, Object[] args)
拋出 IllegalAccessException、IllegalArgumentException、
調用目標異常{
System.out.println("代理前:");
method.invoke(原始, args);
System.out.println("代理后:");
返回空值;
}
}
public static void main(String[] args){
原始原始=新原始();
處理程序處理程序=新處理程序(原始);
If a = (If) Proxy.newProxyInstance(If.class.getClassLoader(),
新類[] { If.class },
處理程序);
a.originalMethod("你好");
}
}
現在,如果處理程序想要調用原始對象的原始方法,首先,它必須有權訪問它。這不會由 Java 代理實現提供。開發人員必須在代碼中手動將此參數傳遞給處理程序實例。
您一定已經注意到,通常將一個名為“proxy”的對象作為參數傳遞給調用處理程序。這是由 Java 反射動態生成的代理對象,而不是我們要代理的對象。因此,開發人員為每個原始類使用單獨的處理程序對象,或者他們也可以使用一些共享對象,如果有任何方法可以調用,他們也可以知道要調用哪個原始對象。您還可以創建一個調用處理程序和一個沒有任何原始對象的接口的代理。您不需要任何類來實現代碼中的接口。動態創建的代理類會自動實現接口。
Java 動態代理在流行技術中被積極使用。在安全框架中可以看到一種常見的用法。
它用于在授權人員應該使用的所有方法中添加安全檢查。使用 Java 動態代理,可以添加安全檢查,導致用戶輸入有效憑據,而無需復制驗證碼來訪問每個方法。
它還可以用于為方法創建日志。這也很容易通過使用代理類來實現。您可以簡單地向原始方法添加額外的代碼,以在最后顯示完整的日志。
以上就是關于“Java動態代理的簡介”,大家如果想了解更多相關知識,不妨來關注一下動力節點Java視頻教程,里面的課程內容從入門到精通,細致全面,通俗易懂,很適合沒有基礎的小伙伴學習,希望對大家能夠有所幫助。
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習