設計模式之代理模式(結構型)
第一章
1.1 模式定義
代理模式:代理模式就是引入一個代理物件,通過代理物件實現對原物件的引用。代理模式是一種物件結構型。
1.2 代理模式包含如下角色
- Subject:抽象主題角色
- Proxy:代理主題角色
- RealSubject:真實主題角色
1.3 模式例子
public class Proxy implements Subject { private RealSubject realSubject = new RealSubject(); public void preRequest() {…...} public void request() { preRequest(); realSubject.request(); postRequest(); } public void postRequest() {……} }
1.4 模式型別
來自:《設計模式》 一書歸納分類
- 遠端(Remote)代理:為一個位於不同的地址空間的物件提供一個本地的代理物件,這個不同的地址空間可以是在同一臺主機中,也可是在另一臺主機中,遠端代理又叫做大使(Ambassador)。
- 虛擬(Virtual)代理:如果需要建立一個資源消耗較大的物件,先建立一個消耗相對較小的物件來表示,真實物件只在需要時才會被真正建立。
- Copy-on-Write代理:它是虛擬代理的一種,把複製(克隆)操作延遲到只有在客戶端真正需要時才執行。一般來說,物件的深克隆是一個開銷較大的操作,Copy-on-Write代理可以讓這個操作延遲,只有物件被用到的時候才被克隆。
- 保護(Protect or Access)代理:控制對一個物件的訪問,可以給不同的使用者提供不同級別的使用許可權。
- 緩衝(Cache)代理:為某一個目標操作的結果提供臨時的儲存空間,以便多個客戶端可以共享這些結果。
- 防火牆(Firewall)代理:保護目標不讓惡意使用者接近。
- 同步化(Synchronization)代理:使幾個使用者能夠同時使用一個物件而沒有衝突。
- 智慧引用(Smart Reference)代理:當一個物件被引用時,提供一些額外的操作,如將此物件被呼叫的次數記錄下來等。
下面介紹一下靜態代理和動態代理
代理模式分為靜態代理和動態代理 • 靜態代理:靜態代理就是編譯階段就生成代理類 來完成對代理物件的一系列操作。
• 動態代理:動態代理是指在執行時動態生成代理類 。即,代理類的位元組碼將在執行時生成並載入當前代理的 ClassLoader。
第二章 靜態代理
靜態代理:靜態代理就是編譯階段就生成代理類 來完成對代理物件的一系列操作。
主題介面:
publicinterface Subject{ abstractpublicvoidrequest(); }
目標物件:
publicclassRealSubjectimplements Subject{ publicvoidrequest(){ System.out.println( " From real subject. " ); } }
代理物件:
publicclassStaticProxySubjectimplements Subject{ privateRealSubjectrealSubject;// 以真實角色作為代理角色的屬性 publicProxySubject(){ } publicvoidrequest(){// 該方法封裝了真實物件的request方法 //懶載入,用的時候才載入 if ( realSubject==null){ realSubject=newRealSubject(); } realSubject.request();// 此處執行真實物件的request方法 } }
編寫客戶端類:
public class Client{ StaticProxySubject sps = new StaticProxySubject(); sps.request(); }
第三章 動態代理
動態代理:動態代理是指在執行時動態生成代理類 。即,代理類的位元組碼將在執行時生成並載入當前代理的 ClassLoader。
生成動態代理的方法有很多: JDK中自帶動態代理,CGlib, javassist等。
3.1 JDK動態代理
Proxy類。該類即為動態代理類,該類最常用的方法為:public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
。
newProxyInstance()方法用於根據傳入的介面型別interfaces返回一個動態建立的代理類的例項,方法中第一個引數loader表示代理類的類載入器,第二個引數interfaces表示被代理類實現的介面列表,第三個引數h表示所指派的呼叫處理程式類。
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class MyInvocationHandler implements InvocationHandler { private Class<?> target;//委託類 public MyInvocationHandler(Class<?> target){ this.target=target; } //實際執行類bind publicObject bind(Class<?> target){ //利用JDK提供的Proxy實現動態代理 returnProxy.newProxyInstance(target.getClassLoader(), new Class[]{target},this); } @Override public Object invoke(Object o, Method method, Object[] args) throws Throwable { /**代理環繞**/ //執行實際的方法 Object invoke = method.invoke(target, args); return invoke; } }
3.2 CGLIB動態代理
CGLIB動態代理實現相關類需要在專案中匯入 cglib-nodep-2.1_3.jar ,主要涉及兩個類:
MethodInterceptor介面。它是代理例項的呼叫處理程式實現的介面,該介面中定義瞭如下方法:public Object intercept(Object proxy, Method method, Object[] arg2,MethodProxy mp);
intercept()方法中第一個引數proxy表示代理類,第二個引數method表示需要代理的方法,第三個引數args表示代理方法的引數陣列,第四個引數mp用 來去呼叫被代理物件方法
package com.demo; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class MyInterceptor implements MethodInterceptor{ private Object target; ;//代理的目標物件 public MyInterceptor(Object target) { this.target = target; } //proxy 在其上呼叫方法的代理例項method攔截的方法args攔截的引數 //invocation 用來去呼叫被代理物件方法 @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy invocation) throws Throwable { //1.記錄日誌 2.時間統計開始3.安全檢查 Object retVal = invocation.invoke(target, args); //4.時間統計結束 return retVal; } //建立代理物件的方法 public Object proxy(Object target) { this.target = target; Enhancer enhancer = new Enhancer();//該類用於生成代理類 enhancer.setSuperclass(this.target.getClass());//設定父類 enhancer.setCallback(this);//設定回撥用物件為本身 return enhancer.create(); } }