導航:首頁 > 編程語言 > 什麼是java動態代理

什麼是java動態代理

發布時間:2025-04-04 18:34:01

『壹』 java 動態代理怎麼理解

JAVA的靜態代理與動態代理比較
一、概念
代理模式是常用的Java 設計模式,它的特徵是代理類與委託類有同樣的介面,代理類主要負責為委託類預處理消息、過濾消息、把消息轉發給委託類,以及事後處理消息等。代理類與委託類之間通常會存在關聯關系,一個代理類的對象與一個委託類的對象關聯,代理類的對象本身並不真正實現服務,而是通過調用委託類的對象的相關方法,來提供特定的服務。按照代理類的創建時期,代理類可分為兩種。

靜態代理類:
程序員創建或由特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。動態代理類:在程序運行時,運用反射機制動態創建而成。

二、靜態代理類
如下, HelloServiceProxy 類是代理類,HelloServiceImpl類是委託類,這兩個類都實現了HelloService介面。其中HelloServiceImpl類是HelloService介面的真正實現者,而HelloServiceProxy類是通過調用HelloServiceImpl 類的相關方法來提供特定服務的。HelloServiceProxy類的echo()方法和getTime()方法會分別調用被代理的HelloServiceImpl 對象的echo()方法和getTime()方法,並且在方法調用前後都會執行一些簡單的列印操作。

由此可見,代理類可以為委託類預處理消息、把消息轉發給委託類和事後處理消息等。

常式1 HelloService.java
package proxy;
import java.util.Date;
public interface HelloService{
public String echo(String msg);
public Date getTime();
}
常式2 HelloServiceImpl.java
package proxy;
import java.util.Date;
public class HelloServiceImpl implements HelloService{
public String echo(String msg){
return "echo:"+msg;
}
public Date getTime(){
return new Date();
}
}
常式3 HelloServiceProxy.java
package proxy;
import java.util.Date;
public class HelloServiceProxy implements HelloService{
private HelloService helloService; //表示被代理的HelloService 實例
public HelloServiceProxy(HelloService helloService){
this.helloService=helloService;
}
public void setHelloServiceProxy(HelloService helloService){
this.helloService=helloService;
}
public String echo(String msg){
System.out.println("before calling echo()"); //預處理
String result=helloService.echo(msg); //調用被代理的HelloService 實例的echo()方法
System.out.println("after calling echo()"); //事後處理
return result;
}
public Date getTime(){
System.out.println("before calling getTime()"); //預處理
Date date=helloService.getTime(); //調用被代理的HelloService 實例的getTime()方法
System.out.println("after calling getTime()"); //事後處理
return date;
}
}
在Client1 類的main()方法中,先創建了一個HelloServiceImpl對象,又創建了一個HelloServiceProxy對象,最後調用HelloServiceProxy對象的echo()方法。
常式4 Client1.java
package proxy;
public class Client1{
public static void main(String args[]){
HelloService helloService=new HelloServiceImpl();
HelloService helloServiceProxy=new HelloServiceProxy(helloService);
System.out.println(helloServiceProxy.echo("hello"));
}
}
運行Client1 類,列印結果如下:
before calling echo()
after calling echo()
echo:hello
常式3 的HelloServiceProxy 類的源代碼是由程序員編寫的,在程序運行前,它的.class文件就已經存在了,這種代理類稱為靜態代理類。

三、動態代理類
與靜態代理類對照的是動態代理類,動態代理類的位元組碼在程序運行時由Java反射機制動態生成,無需程序員手工編寫它的源代碼。動態代理類不僅簡化了編程工作,而且提高了軟體系統的可擴展性,因為Java 反射機制可以生成任意類型的動態代理類。java.lang.reflect 包中的Proxy類和InvocationHandler 介面提供了生成動態代理類的能力。

Proxy類提供了創建動態代理類及其實例的靜態方法。
(1)getProxyClass()靜態方法負責創建動態代理類,它的完整定義如下:

public static Class getProxyClass(ClassLoader loader, Class[] interfaces) throws IllegalArgumentException

參數loader 指定動態代理類的類載入器,參數interfaces 指定動態代理類需要實現的所有介面。

(2)newProxyInstance()靜態方法負責創建動態代理類的實例,它的完整定義如下:

public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler handler) throws
IllegalArgumentException

參數loader 指定動態代理類的類載入器,參數interfaces 指定動態代理類需要實現的所有介面,參數handler 指定與動態代理類關聯的 InvocationHandler 對象。

以下兩種方式都創建了實現Foo介面的動態代理類的實例:
/**** 方式一 ****/
//創建InvocationHandler對象
InvocationHandler handler = new MyInvocationHandler(...);

//創建動態代理類
Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), new Class[] { Foo.class });

//創建動態代理類的實例
Foo foo = (Foo) proxyClass.getConstructor(new Class[] { InvocationHandler.class }).
newInstance(new Object[] { handler });

/**** 方式二 ****/
//創建InvocationHandler對象
InvocationHandler handler = new MyInvocationHandler(...);

//直接創建動態代理類的實例
Foo foo = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[] { Foo.class }, handler);

由Proxy類的靜態方法創建的動態代理類具有以下特點:
動態代理類是public、final和非抽象類型的;
動態代理類繼承了java.lang.reflect.Proxy類;
動態代理類的名字以「$Proxy」開頭;
動態代理類實現getProxyClass()和newProxyInstance()方法中參數interfaces指定的所有介面;

Proxy 類的isProxyClass(Class cl)靜態方法可用來判斷參數指定的類是否為動態代理類。只有通過Proxy類創建的類才是動態代理類;

動態代理類都具有一個public 類型的構造方法,該構造方法有一個InvocationHandler 類型的參數。

由Proxy類的靜態方法創建的動態代理類的實例具有以下特點:
1. 假定變數foo 是一個動態代理類的實例,並且這個動態代理類實現了Foo 介面,那麼「foo instanceof Foo」的值為true。把變數foo強制轉換為Foo類型是合法的:
(Foo) foo //合法

2.每個動態代理類實例都和一個InvocationHandler 實例關聯。Proxy 類的getInvocationHandler(Object proxy)靜態方法返回與參數proxy指定的代理類實例所關聯的InvocationHandler 對象。

3.假定Foo介面有一個amethod()方法,那麼當程序調用動態代理類實例foo的amethod()方法時,該方法會調用與它關聯的InvocationHandler 對象的invoke()方法。

InvocationHandler 介面為方法調用介面,它聲明了負責調用任意一個方法的invoke()方法:
Object invoke(Object proxy,Method method,Object[] args) throws Throwable

參數proxy指定動態代理類實例,參數method指定被調用的方法,參數args 指定向被調用方法傳遞的參數,invoke()方法的返回值表示被調用方法的返回值。

四、最後看一個實例:
HelloServiceProxyFactory 類的getHelloServiceProxy()靜態方法負責創建實現了HelloService介面的動態代理類的實例。

常式5 HelloServiceProxyFactory.java
package proxy;
import java.lang.reflect.*;
public class HelloServiceProxyFactory {
/** 創建一個實現了HelloService 介面的動態代理類的實例
* 參數helloService 引用被代理的HelloService 實例
*/
public static HelloService getHelloServiceProxy(final HelloService helloService){
//創建一個實現了InvocationHandler介面的匿名類的實例
InvocationHandler handler=new InvocationHandler(){
public Object invoke(Object proxy,Method method,Object args[])throws Exception{
System.out.println("before calling "+method); //預處理
Object result=method.invoke(helloService,args);
//調用被代理的HelloService 實例的方法
System.out.println("after calling "+method); //事後處理
return result;
}
};
Class classType=HelloService.class;
return (HelloService)Proxy.newProxyInstance(classType.getClassLoader(),
new Class[]{classType},
handler);
}
}
如下所示的Client2 類先創建了一個HelloServiceImpl 實例,然後創建了一個動態代理類實例helloServiceProxy,最後調用動態代理類實例的echo()方法。
常式6 Client2.java
package proxy;
public class Client2{
public static void main(String args[]){
HelloService helloService=new HelloServiceImpl();
HelloService helloServiceProxy=HelloServiceProxyFactory.getHelloServiceProxy(helloService);
System.out.println("動態代理類的名字為"+helloServiceProxy.getClass().getName());
System.out.println(helloServiceProxy.echo("Hello"));
}
}
運行Client2,列印結果如下:
動態代理類的名字為$Proxy0
before calling public abstract java.lang.String proxy.HelloService.echo(java.lang.String)
after calling public abstract java.lang.String proxy.HelloService.echo(java.lang.String)
echo:Hello
從結果看出,動態代理類的名字為$Proxy0。
PostScript

『貳』 jdk動態代理詳解(通俗易懂,用簡單的方式快速理解動態代理)

動態代理,看似復雜,實則巧妙,它能讓你在Java編程世界中,以動態的方式,增強對象的功能,這在很多場景下都顯得尤為關鍵。以下,我將用最直觀、通俗易懂的方式,帶你理解動態代理的奧秘。

想像一下,你在構建一個復雜的系統,需要在運行時動態地給對象添加或修改行為。動態代理,就是實現這一目標的強有力工具。它利用Java反射機制,通過運行時生成代理對象,從而在不修改原對象代碼的基礎上,實現對方法的增強。

首先,我們來看一段簡單的代碼示例。這里,我們定義了一個介面和一個實現類,然後通過JDK的Proxy類,動態地創建了一個代理對象。代理對象可以調用被代理對象的任何方法,而且,我們還能在代理對象調用方法前或後,添加自定義的邏輯,這就是動態代理的魅力所在。

下面,我將詳細解析這段代碼的每一行,以便於你更好地理解動態代理的運作機制。

首先,我們定義了一個介面MyInterface,包含一個方法`myMethod`。然後,我們創建了一個實現類MyInterfaceImpl,實現了`myMethod`方法。這兩步,我們完成了介面和實現類的定義。

接下來,我們通過Java反射機制中的Proxy類,創建了一個代理對象。Proxy類的newProxyInstance方法,接收三個參數:類載入器、介面數組和調用處理器。在我們的例子中,類載入器用於載入代理類,介面數組包含了要實現的所有介面,調用處理器則負責在方法調用前或後,執行自定義的邏輯。

通過以上步驟,我們成功創建了一個代理對象proxyBean。通過這個代理對象,我們可以調用實現類MyInterfaceImpl中的方法。當代理對象調用被代理類的方法時,實際上會觸發調用處理器中的`invoke`方法。在這里,我們可以在`invoke`方法中,添加任何我們想要的功能,如日誌記錄、性能監控、許可權檢查等,這就是動態代理的強大之處。

總結一下,動態代理的核心在於Java的反射機制和運行時生成代理對象的能力。通過Proxy類,我們可以在不修改原有代碼的情況下,動態地給對象添加功能。這種能力在開發框架、日誌系統、安全監控等場景中,發揮著關鍵作用。

希望本文能夠幫助你理解並掌握動態代理的精髓。如果文章對你有幫助,記得點贊支持哦!

閱讀全文

與什麼是java動態代理相關的資料

熱點內容
程序員電腦如何快速關機 瀏覽:549
安卓貨拉拉怎麼沒聲音 瀏覽:594
分母加減混合運演算法則 瀏覽:928
小伙電腦編程 瀏覽:796
安卓手機打字出錯怎麼辦 瀏覽:778
雲伺服器怎麼掛網頁游戲 瀏覽:801
蘋果手機有什麼練音準的app 瀏覽:638
編譯原理53 瀏覽:535
javacms開源系統源碼下載 瀏覽:609
軟體個人版和伺服器版有什麼區別 瀏覽:668
lol有什麼伺服器在山東 瀏覽:844
命令行關閉窗口 瀏覽:972
手模編程 瀏覽:264
引入賬套顯示需要解壓縮 瀏覽:425
本地電腦連接阿里雲伺服器SQL 瀏覽:48
小米什麼時候推送安卓12 瀏覽:486
如何確保伺服器不斷電不斷網 瀏覽:19
怎麼增加密碼的安全性 瀏覽:212
安卓模擬器如何重啟 瀏覽:902
程序員那麼可愛懷孕第幾集結婚 瀏覽:744