代理模式
在講動態代理之前,需要了解什麼是代理模式,經典的代理模式的uml圖相信大家都見過:
代理模式
RealSubject是需要被代理的對象。我們要在RealSubject之外增加一些處理,就增加一個Proxy類,實現Subject接口,在Proxy類裡持有RealSubject的實例。
Client的請求全部打到Proxy實例上,由Proxy實例來控制是否將請求轉發給RealSubject,或者做額外的處理。
代理模式的優點:對於外界來講,完全無感知,耦合性低。
看一下實例代碼:
這裡對Integer類做了一層代理。這個類的作用在於,在compareTo請求之上增加了信息的打印輸出。
在實際場景中,如果我們需要對多個方法都要做類似的處理,在每個地方都增加同樣的代碼,就顯得有點不夠優雅了。這時候,可以使用java的動態代理。
常用的動態代理有兩種實現方式:JDK和CGLIB
JDK動態代理
看名字就可以知道,這種動態代理是JDK本身就支持的,需要藉助java.lang.reflect下的接口來實現。
創建代理對象
要想創建一個代理對象,需要使用Proxy類的newProxyInstance方法。
這個方法有三個參數:
類加載器。作為Java安全模型的一部分,對於系統類和從因特網上下載下來的類,可以使用不同的類加載器。
Class對象數組,每個元素都是需要實現的接口。
調用處理器。
調用處理器
調用處理器是實現了InvocationHandler接口的類對象。在這個接口中只有一個方法:
動態代理類,需要實現此接口,在接口方法的實現裡做代理邏輯的處理。
創建動態代理
創建一個動態代理對象的工作如下:
獲取 RealSubject上的所有接口列表;
確定要生成的代理類的類名,默認為:com.sun.proxy.$ProxyXXXX ;
根據需要實現的接口信息,在代碼中動態創建 該Proxy類的字節碼;
4 將對應的字節碼轉換為對應的class 對象;
創建InvocationHandler 實例handler,用來處理Proxy所有方法調用;
Proxy的class對象以創建的handler對象為參數,實例化一個proxy對象。
接下來我們看一段代碼實現:
那如何TraceHandler有什麼用呢?
利用TraceHandler可以打印出二分查找的查找順序:
為何toString也會被代理
細心的讀者會發現,上面的程序執行最後有一行
這裡有兩點我們需要知道:
所有的代理類都擴展於Proxy類;
所有的代理類都覆蓋了Object類中的方法toString、equals和hashCode;
針對上面的第二點,所有對代理類的toString、equals和hashCode的方法調用,都會請求到invoke代理實現上去。所以就出現toString方法也被代理的情況了。
閱讀更多 果大爺的幸福生活 的文章