java程序員面試必備知識:java的動態代理

代理模式

在講動態代理之前,需要了解什麼是代理模式,經典的代理模式的uml圖相信大家都見過:

java程序員面試必備知識:java的動態代理

代理模式

RealSubject是需要被代理的對象。我們要在RealSubject之外增加一些處理,就增加一個Proxy類,實現Subject接口,在Proxy類裡持有RealSubject的實例。

Client的請求全部打到Proxy實例上,由Proxy實例來控制是否將請求轉發給RealSubject,或者做額外的處理。

代理模式的優點:對於外界來講,完全無感知,耦合性低。

看一下實例代碼:

java程序員面試必備知識:java的動態代理

這裡對Integer類做了一層代理。這個類的作用在於,在compareTo請求之上增加了信息的打印輸出。

在實際場景中,如果我們需要對多個方法都要做類似的處理,在每個地方都增加同樣的代碼,就顯得有點不夠優雅了。這時候,可以使用java的動態代理。

常用的動態代理有兩種實現方式:JDK和CGLIB

JDK動態代理

看名字就可以知道,這種動態代理是JDK本身就支持的,需要藉助java.lang.reflect下的接口來實現。

創建代理對象

要想創建一個代理對象,需要使用Proxy類的newProxyInstance方法。

java程序員面試必備知識:java的動態代理

這個方法有三個參數:

  1. 類加載器。作為Java安全模型的一部分,對於系統類和從因特網上下載下來的類,可以使用不同的類加載器。

  2. Class對象數組,每個元素都是需要實現的接口。

  3. 調用處理器。

調用處理器

調用處理器是實現了InvocationHandler接口的類對象。在這個接口中只有一個方法:

java程序員面試必備知識:java的動態代理

動態代理類,需要實現此接口,在接口方法的實現裡做代理邏輯的處理。

創建動態代理

創建一個動態代理對象的工作如下:

  1. 獲取 RealSubject上的所有接口列表;

  2. 確定要生成的代理類的類名,默認為:com.sun.proxy.$ProxyXXXX ;

  3. 根據需要實現的接口信息,在代碼中動態創建 該Proxy類的字節碼;

    4 將對應的字節碼轉換為對應的class 對象;

  4. 創建InvocationHandler 實例handler,用來處理Proxy所有方法調用;

  5. Proxy的class對象以創建的handler對象為參數,實例化一個proxy對象。

    接下來我們看一段代碼實現:

java程序員面試必備知識:java的動態代理

java程序員面試必備知識:java的動態代理

那如何TraceHandler有什麼用呢?

利用TraceHandler可以打印出二分查找的查找順序:

java程序員面試必備知識:java的動態代理

為何toString也會被代理

細心的讀者會發現,上面的程序執行最後有一行

java程序員面試必備知識:java的動態代理

這裡有兩點我們需要知道:

  • 所有的代理類都擴展於Proxy類;

  • 所有的代理類都覆蓋了Object類中的方法toString、equals和hashCode;

    針對上面的第二點,所有對代理類的toString、equals和hashCode的方法調用,都會請求到invoke代理實現上去。所以就出現toString方法也被代理的情況了。


分享到:


相關文章: