06代理模式
一、代理模式定義
1.代理模式是指為其他物件提供一種代理,以控制對這個物件的訪問,屬於結構型模式。
2.在某些情況下,一個物件不適合或者不能直接引用另一個物件,而代理物件可以在客戶端和目標物件之間起到中介的作用。
3.代理模式一般包含三種角色:
A.抽象主題角色(Subject):抽象主題類的主要職責是宣告真是主題與代理的共同介面方法,該類可以是介面也可以是抽象類
B.真實主題角色(RealSubject):該類也被稱為被代理類,該類定義了代理所表示的真實物件,是負責執行系統真正的業務邏輯物件
C.代理主題角色(Proxy):也被稱為代理類,其內部持有RealSubject的引用,因此具備完全的對RealSubject的代理權。客戶端呼叫代理物件的方法,同時也呼叫被代理物件的方法,但是會在代理物件前後增加 一些處理程式碼
4.在程式碼中,一般代理會被理解為程式碼增強,實際上就是在原始碼邏輯前後增加一些程式碼邏輯,而使呼叫者無感知。代理模式屬於結構型模式,分為靜態代理和動態代理
5.代理模式的目的:一是保護目標物件,二是增強目標物件
二、代理模式的通用寫法
1.程式碼示例:
1 /** 2 * 代理主題角色 3 */ 4 public interface ISubject { 5 void request(); 6 } 7 8 /** 9 * 真實主題角色 10 */ 11 public class RealSubject implements ISubject { 12 @Override13 public void request() { 14 System.out.println("real service is called."); 15 } 16 } 17 18 /** 19 * 代理主題角色 20 */ 21 public class Proxy implements ISubject { 22 23 private ISubject subject; 24 25 public Proxy(ISubject subject){ 26 this.subject = subject; 27 } 2829 @Override 30 public void request() { 31 before(); 32 subject.request(); 33 after(); 34 } 35 36 public void before(){ 37 System.out.println("called before request()."); 38 } 39 40 public void after(){ 41 System.out.println("called after request()."); 42 } 43 } 44 45 public class GeneralProxyTest { 46 public static void main(String[] args) { 47 Proxy proxy = new Proxy(new RealSubject()); 48 proxy.request(); 49 } 50 }
三、動態代理
1.上面通用寫法實際上是一種靜態代理,動態代理分為jdk動態代理和cglib動態代理
2.jdk動態代理示例
1 public interface IPerson { 2 void findLove(); 3 } 4 5 public class ZhangSan implements IPerson { 6 @Override 7 public void findLove() { 8 System.out.println("膚白貌美大長腿"); 9 } 10 } 11 12 public class JdkMeiPo implements InvocationHandler { 13 14 private IPerson target; 15 16 public IPerson getInstance(IPerson target){ 17 this.target = target; 18 Class<? extends IPerson> clazz = target.getClass(); 19 return (IPerson) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this); 20 } 21 22 @Override 23 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 24 before(); 25 Object result = method.invoke(this.target, args); 26 after(); 27 return result; 28 } 29 30 private void before(){ 31 System.out.println("我是媒婆:已經收集到你的需求,開始物色"); 32 } 33 34 private void after(){ 35 System.out.println("雙方同意,開始交往"); 36 } 37 } 38 39 public class JdkDynamicProxyTest { 40 public static void main(String[] args) { 41 JdkMeiPo jdkMeiPo = new JdkMeiPo(); 42 IPerson instance = jdkMeiPo.getInstance(new ZhangSan()); 43 instance.findLove(); 44 } 45 46 }
A.jdk動態代理採用位元組碼重組,重新生成物件來替代原始物件,以達到動態代理的目的。繼承Proxy類並實現被代理類的所有介面,重寫方法
B.jdk動態代理生成物件步驟:
a.獲取被代理物件的引用,並獲取它的所有介面,反射獲取
b.jdk動態代理類重新生成一個新的類,同時新的類要實現被代理類實現的所有介面
c.動態生成java程式碼,新加的業務邏輯方法由一定的邏輯程式碼呼叫
d.編譯新生成的java程式碼為.class檔案
e.重新載入到jvm執行
3.cglib動態程式碼示例
1 public class Customer { 2 public void findLove(){ 3 System.out.println("有車有房有存款"); 4 } 5 } 6 7 public class CglibMeiPo implements MethodInterceptor { 8 9 public Object getInstance(Class<?> clazz) throws Exception{ 10 Enhancer enhancer = new Enhancer(); 11 enhancer.setSuperclass(clazz); 12 enhancer.setCallback(this); 13 return enhancer.create(); 14 } 15 16 @Override 17 public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { 18 before(); 19 Object obj = methodProxy.invokeSuper(o,objects); 20 after(); 21 return obj; 22 } 23 24 private void before(){ 25 System.out.println("我是媒婆:我要給你找物件,現在已經確認你的需求"); 26 System.out.println("開始物色"); 27 } 28 29 private void after(){ 30 System.out.println("如果合適的話,就準備辦事"); 31 } 32 33 }
A.cglib代理的目標物件不需要實現介面,它是通過動態繼承目標物件實現動態代理的
B.cglib會生成三個.class:繼承目標類的,代理和被代理的FastClass
C.FastClass機制:為代理類和被代理類各生成一個類,這個類會為代理類或被代理類的方法分配一個index(int型別);這個index當作一個入參,FastClass就可以直接定位要呼叫的方法並直接進行呼叫,省去了反射呼叫,所以呼叫效率比JDK代理高
4.Cglib和Jdk動態代理對比
A.jdk動態代理實現了被代理物件的介面,cglib代理繼承了被代理物件
B.jdk動態代理和cglib代理都在執行期生成位元組碼,jdk動態代理直接寫Class位元組碼,cglib代理使用ASM框架寫Class位元組碼,cglib代理實現更復雜,生成代理類效率比jdk動態代理低
C.jdk動態代理呼叫代理方法是通過反射機制呼叫的,cglib代理是通過FastClass機制直接呼叫方法的,cglib代理的執行效率更高
四、靜態代理和動態代理的本質區別
1.靜態代理只能通過手動完成代理操作,如果被代理類增加了新的方法,代理類需要同步增加,違反了開閉原則
2.動態代理採用在執行時生成程式碼的方式,取消了對被代理類的擴充套件限制,遵循開閉原則
3.若動態代理要對目標類的增強邏輯進行擴充套件,結合策略模式,只需要新增策略類即可,無須修改代理類的程式碼
五、代理模式的優缺點
1.優點:
A.代理模式能將代理物件與真實被呼叫目標物件分離
B.在一定程度上降低了系統的耦合性,擴充套件性好
C.可以起到保護目標物件的作用
D.可以增強目標物件的功能
2.缺點:
A.代理模式會造成系統設計中類的數量增加
B.在客戶端和目標物件中增加一個代理物件,會導致請求處理速度變慢
C.增加了系統複雜度