1. 程式人生 > >jdk動態代理與CGLib的區別

jdk動態代理與CGLib的區別

jdk動態代理與CGLib的區別

2017年09月20日 22:31:10 E_k_in 閱讀數:5151

動態代理proxy與CGLib的區別

標籤: 代理模式

2013-09-03 08:50 19977人閱讀 評論(4) 收藏 舉報

版權宣告:本文為博主原創文章,未經博主允許不得轉載。

昨天被人問及動態代理與CGlib的區別,趕緊回顧一下:

 

  1. 什麼是代理?
  2. 靜態代理與動態代理
  3. 靜態代理例項
  4. JDK動態代理例項
  5. CGLib 簡介
  6. CGLib 與JDK動態代理的區別

 

    代理模式是Java中常見的一種模式,英文名字叫走Proxy或者Surrogate,代理的本意是一個人代表另一個人,或者一個機構代表另一個機構,採取行動,因而,代理和現實生活中的中介有很大的類似,你買房子、賣房子,可以自己去操作,但是需要了解和買賣房產無關的細節,如契稅等,而找一箇中介,則不用關心這些與買賣房產無直接關係的中間細節,只關心業務本身。

  靜態代理UML類圖

 模式中包含的角色及其職責

Subject:抽象主題角色,抽象主題類可以是抽象類,也可以是介面,是一個最普通的業務型別定義,無特殊要求。

RealSubject:具體主題角色,也叫被委託角色、被代理角色。是業務邏輯的具體執行者。

Proxy:代理主題角色,也叫委託類、代理類。它把所有抽象主題類定義的方法給具體主題角色實現,並且在具體主題角色處理完畢前後做預處理和善後工作。(最簡單的比如列印日誌):

  Subject:

 

[java] view plain copy

  1. /** 
  2.  
  3.  * 抽象主題,定義主要功能 
  4.  
  5.  */  
  6.   
  7. publicinterface Subject {  
  8.   
  9.    publicvoid operate();  
  10.   
  11. }  
 
  1. /**

  2.  
  3. * 抽象主題,定義主要功能

  4.  
  5. */

  6.  
  7. publicinterface Subject {

  8.  
  9. publicvoid operate();

  10.  
  11. }


RealSubject:

 

  

[java] view plain copy

  1. /** 
  2.  
  3.  * 具體主題 
  4.  
  5.  */  
  6.   
  7. publicclass RealSubject implements Subject{  
  8.   
  9.    
  10.   
  11.    @Override  
  12.   
  13.    publicvoid operate() {  
  14.   
  15.         System.out.println("realsubject operatestarted......");  
  16.   
  17.    }  
  18.   
  19. }  
 
  1. /**

  2.  
  3. * 具體主題

  4.  
  5. */

  6.  
  7. publicclass RealSubject implements Subject{

  8.  
  9.  
  10.  
  11. @Override

  12.  
  13. publicvoid operate() {

  14.  
  15. System.out.println("realsubject operatestarted......");

  16.  
  17. }

  18.  
  19. }


代理類Proxy:

 

 

[java] view plain copy

  1. /** 
  2.  
  3.  * 代理類 
  4.  
  5.  */  
  6.   
  7. publicclass Proxy implements Subject{  
  8.   
  9.    
  10.   
  11.    private Subject subject;  
  12.   
  13.    
  14.   
  15.    public Proxy(Subject subject) {  
  16.   
  17.         this.subject = subject;  
  18.   
  19.    }  
  20.   
  21.    
  22.   
  23.    @Override  
  24.   
  25.    publicvoid operate() {  
  26.   
  27.         System.out.println("before operate......");  
  28.   
  29.         subject.operate();  
  30.   
  31.         System.out.println("after operate......");  
  32.   
  33.    }  
  34.   
  35. }  
 
  1. /**

  2.  
  3. * 代理類

  4.  
  5. */

  6.  
  7. publicclass Proxy implements Subject{

  8.  
  9.  
  10.  
  11. private Subject subject;

  12.  
  13.  
  14.  
  15. public Proxy(Subject subject) {

  16.  
  17. this.subject = subject;

  18.  
  19. }

  20.  
  21.  
  22.  
  23. @Override

  24.  
  25. publicvoid operate() {

  26.  
  27. System.out.println("before operate......");

  28.  
  29. subject.operate();

  30.  
  31. System.out.println("after operate......");

  32.  
  33. }

  34.  
  35. }


客戶端:

 

 

[java] view plain copy

  1. /** 
  2.  * 客戶 
  3.  */  
  4. publicclass Client {  
  5.    /** 
  6.     * @param args 
  7.     */  
  8.    publicstaticvoid main(String[] args) {  
  9.         Subject subject = new RealSubject();  
  10.         Proxy proxy = new Proxy(subject);  
  11.         proxy.operate();  
  12.    }  
  13. }  
 
  1. /**

  2. * 客戶

  3. */

  4. publicclass Client {

  5. /**

  6. * @param args

  7. */

  8. publicstaticvoid main(String[] args) {

  9. Subject subject = new RealSubject();

  10. Proxy proxy = new Proxy(subject);

  11. proxy.operate();

  12. }

  13. }

 

 

 

 

     代理模式的適用,總結為:代理類主要負責為委託類預處理訊息、過濾訊息、把訊息轉發給委託類,以及事後處理訊息等

   代理模式的用途,可以分為如下幾種(From GOF):
 

(1)遠端代理(Remote Proxy)  ---A remote proxy provides a local representative for an object in a different address space.為遠端物件提供一個本地的代理物件, 典型的例子如RMI, EJB,local bean 為remote 介面物件提供一個stub

(2)虛擬代理(Virtual Proxy) –  A virtual proxy creates expensive objects on demand.允許記憶體開銷較大的物件在需要的時候建立。只有我們真正需要這個物件的時候才建立。

  虛擬代理模式(Virtual Proxy)是一種節省記憶體的技術,它建議建立那些佔用大量記憶體或處理複雜的物件時,把建立這類物件推遲到使用它的時候。在特定的應用中,不同部分的功能由不同的物件組成,應用啟動的時候,不會立即使用所有的物件。在這種情況下,虛擬代理模式建議推遲物件的建立直到應用程式需要它為止。物件被應用第一次引用時建立並且同一個例項可以被重用。這種方法優缺點並存。
  
  優點:
  
  這種方法的優點是,在應用程式啟動時,由於不需要建立和裝載所有的物件,因此加速了應用程式的啟動。
  
  缺點:
  
  因為不能保證特定的應用程式物件被建立,在訪問這個物件的任何地方,都需要檢測確認它不是空(null)。也就是,這種檢測的時間消耗是最大的缺點。
  
  應用虛擬代理模式,需要設計一個與真實物件具有相同介面的單獨物件(指虛擬代理)。不同的客戶物件可以在建立和使用真實物件地方用相應的虛擬物件來代替。虛擬物件把真實物件的引用作為它的例項變數維護。代理物件不要自動建立真實物件,當客戶需要真實物件的服務時,呼叫虛擬代理物件上的方法,並且檢測真實物件是否被建立。
  
  如果真實物件已經建立,代理把呼叫轉發給真實物件
  
  如果真實物件沒有被建立:
  
  1)代理物件建立真實物件
  
  2)代理物件把這個物件分配給引用變數。
  
  3)代理把呼叫轉發給真實物件
  
  按照這種安排,驗證物件存在和轉發方法呼叫這些細節對於客戶是不可見的。客戶物件就像和真實物件一樣與代理物件進行互動。因此客戶從檢測真實物件是否為null中解脫出來,另外,由於建立代理物件在時間和處理複雜度上要少於建立真實物件。因此,在應用程式啟動的時候,用代理物件代替真實物件初始化。

(3)寫入時複製代理(Copy-On-Write Proxy) – 用來控制物件的複製,方法是延遲物件的複製,直到客戶真的需要為止。是虛擬代理的一個變體。

(4)保護代理(Protection (Access)Proxy) –  A protection proxy controls access to the original object. Protection proxies are useful when objects should have different access rights.為不同的客戶提供不同級別的目標物件訪問許可權

(5)快取代理(Cache Proxy) – 為開銷大的運算結果提供暫時儲存,它允許多個客戶共享結果,以減少計算或網路延遲。

(6)防火牆代理(Firewall Proxy) – 控制網路資源的訪問,保護主題免於惡意客戶的侵害。

(7)同步代理(SynchronizationProxy) –在多執行緒的情況下為主題提供安全的訪問。

(8)智慧引用代理(Smart ReferenceProxy) -  A smart reference is a replacement for a bare pointer that performs additional actions when an object is accessed。當一個物件被引用時,提供一些額外的操作,比如將對此物件呼叫的次數記錄下來等。

(9)複雜隱藏代理(Complexity HidingProxy) – 用來隱藏一個類的複雜集合的複雜度,並進行訪問控制。有時候也稱為外觀代理(Façade Proxy),這不難理解。複雜隱藏代理和外觀模式是不一樣的,因為代理控制訪問,而外觀模式是不一樣的,因為代理控制訪問,而外觀模式只提供另一組介面。

 

   2.靜態代理與動態代理

代理分為靜態代理和動態代理

   按照代理建立的時期,可以分為動態代理和靜態代理:

 靜態代理:由程式設計師或者自動生成工具生成代理類,然後進行代理類的編譯和執行。在代理類、委託類執行之前,代理類已經以.class的格式存在。

 靜態代理:在程式執行時,由反射機制動態建立而成。

 

 3.靜態代理例項

    靜態代理例項:

     首先需要一個介面:

      

[java] view plain copy

  1. package net.battier.dao;  
  2.   
  3. /** 
  4.  * 定義一個賬戶介面 
  5.  *  
  6.  * @author Administrator 
  7.  *  
  8.  */  
  9. public interface Count {  
  10.     // 檢視賬戶方法  
  11.     public void queryCount();  
  12.   
  13.     // 修改賬戶方法  
  14.     public void updateCount();  
  15.   
  16. }  
 
  1. package net.battier.dao;

  2.  
  3. /**

  4. * 定義一個賬戶介面

  5. *

  6. * @author Administrator

  7. *

  8. */

  9. public interface Count {

  10. // 檢視賬戶方法

  11. public void queryCount();

  12.  
  13. // 修改賬戶方法

  14. public void updateCount();

  15.  
  16. }

  然後是委託類,也就是介面的真正實現類,內涵主要的業務邏輯:

 

   

[java] view plain copy

  1. package net.battier.dao.impl;  
  2.   
  3. import net.battier.dao.Count;  
  4.   
  5. /** 
  6.  * 委託類(包含業務邏輯) 
  7.  *  
  8.  * @author Administrator 
  9.  *  
  10.  */  
  11. public class CountImpl implements Count {  
  12.   
  13.     @Override  
  14.     public void queryCount() {  
  15.         System.out.println("檢視賬戶方法...");  
  16.   
  17.     }  
  18.   
  19.     @Override  
  20.     public void updateCount() {  
  21.         System.out.println("修改賬戶方法...");  
  22.   
  23.     }  
  24.   
  25. }  
 
  1. package net.battier.dao.impl;

  2.  
  3. import net.battier.dao.Count;

  4.  
  5. /**

  6. * 委託類(包含業務邏輯)

  7. *

  8. * @author Administrator

  9. *

  10. */

  11. public class CountImpl implements Count {

  12.  
  13. @Override

  14. public void queryCount() {

  15. System.out.println("檢視賬戶方法...");

  16.  
  17. }

  18.  
  19. @Override

  20. public void updateCount() {

  21. System.out.println("修改賬戶方法...");

  22.  
  23. }

  24.  
  25. }

  26.  

   最後是代理類:

 

        

[java] view plain copy

  1. CountProxy.java  
  2. package net.battier.dao.impl;  
  3.   
  4. import net.battier.dao.Count;  
  5.   
  6. /** 
  7.  * 這是一個代理類(增強CountImpl實現類) 
  8.  *  
  9.  * @author Administrator 
  10.  *  
  11.  */  
  12. public class CountProxy implements Count {  
  13.     private CountImpl countImpl;  
  14.   
  15.     /** 
  16.      * 覆蓋預設構造器 
  17.      *  
  18.      * @param countImpl 
  19.      */  
  20.     public CountProxy(CountImpl countImpl) {  
  21.         this.countImpl = countImpl;  
  22.     }  
  23.   
  24.     @Override  
  25.     public void queryCount() {  
  26.         System.out.println("事務處理之前");  
  27.         // 呼叫委託類的方法;  
  28.         countImpl.queryCount();  
  29.         System.out.println("事務處理之後");  
  30.     }  
  31.   
  32.     @Override  
  33.     public void updateCount() {  
  34.         System.out.println("事務處理之前");  
  35.         // 呼叫委託類的方法;  
  36.         countImpl.updateCount();  
  37.         System.out.println("事務處理之後");  
  38.   
  39.     }  
  40.   
  41. }  
 
  1. CountProxy.java

  2. package net.battier.dao.impl;

  3.  
  4. import net.battier.dao.Count;

  5.  
  6. /**

  7. * 這是一個代理類(增強CountImpl實現類)

  8. *

  9. * @author Administrator

  10. *

  11. */

  12. public class CountProxy implements Count {

  13. private CountImpl countImpl;

  14.  
  15. /**

  16. * 覆蓋預設構造器

  17. *

  18. * @param countImpl

  19. */

  20. public CountProxy(CountImpl countImpl) {

  21. this.countImpl = countImpl;

  22. }

  23.  
  24. @Override

  25. public void queryCount() {

  26. System.out.println("事務處理之前");

  27. // 呼叫委託類的方法;

  28. countImpl.queryCount();

  29. System.out.println("事務處理之後");

  30. }

  31.  
  32. @Override

  33. public void updateCount() {

  34. System.out.println("事務處理之前");

  35. // 呼叫委託類的方法;

  36. countImpl.updateCount();

  37. System.out.println("事務處理之後");

  38.  
  39. }

  40.  
  41. }

執行:

   

[java] view plain copy

  1. package com.mahoutchina.pattern.proxy;  
  2.   
  3. public class CountTest {  
  4.   
  5.     /** 
  6.      * @param args 
  7.      */  
  8.     public static void main(String[] args) {  
  9.         CountImpl countImpl = new CountImpl();    
  10.         CountProxy countProxy = new CountProxy(countImpl);    
  11.         countProxy.updateCount();    
  12.         countProxy.queryCount();   
  13.   
  14.     }  
  15.   
  16. }  
 
  1. package com.mahoutchina.pattern.proxy;

  2.  
  3. public class CountTest {

  4.  
  5. /**

  6. * @param args

  7. */

  8. public static void main(String[] args) {

  9. CountImpl countImpl = new CountImpl();

  10. CountProxy countProxy = new CountProxy(countImpl);

  11. countProxy.updateCount();

  12. countProxy.queryCount();

  13.  
  14. }

  15.  
  16. }

  從靜態代理中可以看出:

 

    1.介面:代理類需要實現一個介面,這個介面和委託類的介面是一樣的,這樣proxy才能和委託類行為表現一致

    2. 方法(Method):由於介面限制,proxy類中也要有interface中的各個方法,這就造成了程式碼重複

   

4.動態代理例項
    動態代理類克服了proxy需要繼承專一的interface介面,並且要實現相應的method的缺陷。

 

latex-table

 

 

java動態代理類位於java.lang.reflect包下,一般主要涉及到以下兩個類:

  1. Interface InvocationHandler:該介面中僅定義了一個方法Object:invoke(Object obj,Method method, Object[] args)。在實際使用時,第一個引數obj一般是指代理 類,method是被代理的方法,如上例中的request(),args為該方法的引數陣列。 這個抽 象方法在代理類中動態實現。
  2. Proxy:該類即為動態代理類,作用類似於上例中的ProxySubject。
  3. Protected Proxy(InvocationHandler h):建構函式,估計用於給內部的h賦值。
  4. Static Class getProxyClass (ClassLoader loader, Class[] interfaces):獲得一個 代理類,其中loader是類裝載器,interfaces是真實類所擁有的全部介面的陣列。
  5. Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理類的一個例項,返回後的代理類可以當作被代理類使用 (可使用被代理類的在Subject介面中宣告過的方法)。

在使用動態代理類時,我們必須實現InvocationHandler, 以上面的程式碼為例:

  Subject:

[java] view plain copy

  1. public  interface Subject {  
  2.   abstract  public  void request();  
  3. }  
 
  1. public interface Subject {

  2. abstract public void request();

  3. }


具體Subject:[java] view plain copy

  1. // 具體角色RealSubject:  
  2. public  class RealSubject implements Subject {  
  3.   public RealSubject() {}  
  4.   
  5.   public  void request() {  
  6.     System.out.println( " From real subject. " );  
  7.  }  
  8.   
  9. }  
 
  1. // 具體角色RealSubject:

  2. public class RealSubject implements Subject {

  3. public RealSubject() {}

  4.  
  5. public void request() {

  6. System.out.println( " From real subject. " );

  7. }

  8.  
  9. }

代理處理器(ProxyHandler):
[java] view plain copy

  1. import java.lang.reflect.Method;  
  2. import java.lang.reflect.InvocationHandler;  
  3.   
  4. public  class DynamicSubject implements InvocationHandler {  
  5.   private Object sub;  
  6.   public DynamicSubject() {}  
  7.   
  8.   public DynamicSubject(Object obj) {  
  9.     sub = obj;  
  10.   }  
  11.   
  12.   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  13.     System.out.println( " before calling "  + method);  
  14.     method.invoke(sub,args);  
  15.   
  16.     System.out.println( " after calling "  + method);  
  17.     return  null ;  
  18.   }  
  19. }  
 
  1. import java.lang.reflect.Method;

  2. import java.lang.reflect.InvocationHandler;

  3.  
  4. public class DynamicSubject implements InvocationHandler {

  5. private Object sub;

  6. public DynamicSubject() {}

  7.  
  8. public DynamicSubject(Object obj) {

  9. sub = obj;

  10. }

  11.  
  12. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

  13. System.out.println( " before calling " + method);

  14. method.invoke(sub,args);

  15.  
  16. System.out.println( " after calling " + method);

  17. return null ;

  18. }

  19. }

該代理類的內部屬性為Object類,實際使用時通過該類的建構函式DynamicSubject(Object obj)對其賦值;此外,在該類還實現了invoke方法,該方法中的

method.invoke(sub,args);

其實就是呼叫被代理物件的將要被執行的方法,方法引數sub是實際的被代理物件,args為執 行被代理物件相應操作所需的引數。通過動態代理類,我們可以在呼叫之前或之後執行一些 相關操作。

[java] view plain copy

  1. // 客戶端:  
  2. import java.lang.reflect.InvocationHandler;  
  3. import java.lang.reflect.Proxy;  
  4. import java.lang.reflect.Constructor;  
  5. import java.lang.reflect.Method;  
  6.   
  7. public class Client {  
  8.   
  9.   static public void main(String[] args) throws Throwable {  
  10.    RealSubject rs = new RealSubject(); // 在這裡指定被代理類  
  11.    InvocationHandler ds = new DynamicSubject(rs);  
  12.    Class cls = rs.getClass();  
  13.   
  14.    // 以下是一次性生成代理  
  15.    Subject subject = (Subject) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),ds );  
  16.    subject.request();  
  17.   }  
  18. }  
 
  1. // 客戶端:

  2. import java.lang.reflect.InvocationHandler;

  3. import java.lang.reflect.Proxy;

  4. import java.lang.reflect.Constructor;

  5. import java.lang.reflect.Method;

  6.  
  7. public class Client {

  8.  
  9. static public void main(String[] args) throws Throwable {

  10. RealSubject rs = new RealSubject(); // 在這裡指定被代理類

  11. InvocationHandler ds = new DynamicSubject(rs);

  12. Class cls = rs.getClass();

  13.  
  14. // 以下是一次性生成代理

  15. Subject subject = (Subject) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),ds );

  16. subject.request();

  17. }

  18. }


通過這種方式,被代理的物件(RealSubject)可以在執行時動態改變,需要控制的介面 (Subject介面)可以在執行時改變,控制的方式(DynamicSubject類)也可以動態改變,從而實 現了非常靈活的動態代理關係。

 

 

 

 

從JDK 1.3以來,Java 語言通過java.lang.reflex庫提供的三個類直接支援代理:

     java.lang.reflect.Proxy,java.lang.reflect.InvocationHandler 和Method.

    Proxy類在執行時動態建立代理物件,這也是dynamic proxy的由來,下面是類圖,其中最重要的是newProxyInstance,這個方法中,指明瞭將要代理的類的載入器,業務類介面,以及代理類要執行動作的呼叫處理器(InvokeHandler)

 

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, 
InvocationHandler h) 
                               throws IllegalArgumentException 
引數說明: 
ClassLoader loader:類載入器 
Class<?>[] interfaces:得到全部的介面 
InvocationHandler h:得到InvocationHandler介面的子類例項 

Ps:類載入器 
在Proxy類中的newProxyInstance()方法中需要一個ClassLoader類的例項,ClassLoader實際上對應的是類載入器,在Java中主要有一下三種類載入器; 
Booststrap ClassLoader:此載入器採用C++編寫,一般開發中是看不到的; 
Extendsion ClassLoader:用來進行擴充套件類的載入,一般對應的是jre\lib\ext目錄中的類; 
AppClassLoader:(預設)載入classpath指定的類,是最常使用的是一種載入器。 

   當系統有了一個代理物件之後,對原方法的呼叫會首先被分派到一個呼叫處理器(Invocation Handler).InvocationHandler 介面如下圖所示:

    

  程式碼:

    介面:

[java] view plain copy

  1. package com.mahoutchina.pattern.proxy.dynamicproxy;  
  2.   
  3. public interface BookFacade {  
  4.     public void addBook();  
  5.     public void deleteBook();  
  6. }  
 
  1. package com.mahoutchina.pattern.proxy.dynamicproxy;

  2.  
  3. public interface BookFacade {

  4. public void addBook();

  5. public void deleteBook();

  6. }

  實際業務類:

 

 

[java] view plain copy

  1. package com.mahoutchina.pattern.proxy.dynamicproxy;  
  2.   
  3. public class BookFacadeImpl implements BookFacade {  
  4.   
  5.     @Override  
  6.     public void addBook() {  
  7.         System.out.println("add book logic is running。。。");   
  8.     }  
  9.   
  10.     @Override  
  11.     public void deleteBook() {  
  12.         System.out.println("delete book logic is running。。。");  
  13.           
  14.     }  
  15.       
  16.   
  17. }  
 
  1. package com.mahoutchina.pattern.proxy.dynamicproxy;

  2.  
  3. public class BookFacadeImpl implements BookFacade {

  4.  
  5. @Override

  6. public void addBook() {

  7. System.out.println("add book logic is running。。。");

  8. }

  9.  
  10. @Override

  11. public void deleteBook() {

  12. System.out.println("delete book logic is running。。。");

  13.  
  14. }

  15.  
  16.  
  17. }

  動態代理類:

 

    

[java] view plain copy

  1. package com.mahoutchina.pattern.proxy.dynamicproxy;  
  2.   
  3. import java.lang.reflect.InvocationHandler;  
  4. import java.lang.reflect.Method;  
  5. import java.lang.reflect.Proxy;  
  6.   
  7. public class BookFacadeProxy implements InvocationHandler {  
  8.     private Object target;  
  9.   
  10.     /** 
  11.      *  
  12.      * @param target 
  13.      * @return 
  14.      */  
  15.     public Object bind(Object target) {  
  16.         this.target = target;  
  17.         // 取得代理物件  
  18.         return Proxy.newProxyInstance(target.getClass().getClassLoader(),  
  19.                 target.getClass().getInterfaces(), this);  
  20.     }  
  21.   
  22.     @Override  
  23.     public Object invoke(Object proxy, Method method, Object[] args)  
  24.             throws Throwable {  
  25.         Object result=null;  
  26.         System.out.println("Proxy start...");  
  27.         System.out.println("method name:"+method.getName());  
  28.         result=method.invoke(target, args);  
  29.         System.out.println("Proxy end...");  
  30.         return result;  
  31.     }  
  32.   
  33. }  
 
  1. package com.mahoutchina.pattern.proxy.dynamicproxy;

  2.  
  3. import java.lang.reflect.InvocationHandler;

  4. import java.lang.reflect.Method;

  5. import java.lang.reflect.Proxy;

  6.  
  7. public class BookFacadeProxy implements InvocationHandler {

  8. private Object target;

  9.  
  10. /**

  11. *

  12. * @param target

  13. * @return

  14. */

  15. public Object bind(Object target) {

  16. this.target = target;

  17. // 取得代理物件

  18. return Proxy.newProxyInstance(target.getClass().getClassLoader(),

  19. target.getClass().getInterfaces(), this);

  20. }

  21.  
  22. @Override

  23. public Object invoke(Object proxy, Method method, Object[] args)

  24. throws Throwable {

  25. Object result=null;

  26. System.out.println("Proxy start...");

  27. System.out.println("method name:"+method.getName());

  28. result=method.invoke(target, args);

  29. System.out.println("Proxy end...");

  30. return result;

  31. }

  32.  
  33. }

  測試類:

 

   

[java] view plain copy

  1. package com.mahoutchina.pattern.proxy.dynamicproxy;  
  2.   
  3. ublic class TestProxy {  
  4.   
  5. /** 
  6.  * @param args 
  7.  */  
  8. public static void main(String[] args) {  
  9.     BookFacadeProxy proxy = new BookFacadeProxy();  
  10.     BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());  
  11.     bookProxy.addBook();  
  12.     bookProxy.deleteBook();  
  13. }  
 
  1. package com.mahoutchina.pattern.proxy.dynamicproxy;

  2.  
  3. public class TestProxy {

  4.  
  5. /**

  6. * @param args

  7. */

  8. public static void main(String[] args) {

  9. BookFacadeProxy proxy = new BookFacadeProxy();

  10. BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());

  11. bookProxy.addBook();

  12. bookProxy.deleteBook();

  13. }

  14.  
  15. }

   對於JDK 的Proxy,有以下幾點:

 

    1)Interface:對於JDK proxy,業務類是需要一個Interface的,這也是一個缺陷

    2)Proxy,Proxy 類是動態產生的,這個類在呼叫Proxy.newProxyInstance(targetCls.getClassLoader, targetCls.getInterface,InvocationHander)之後,會產生一個Proxy類的例項。實際上這個Proxy類也是存在的,不僅僅是類的例項。這個Proxy類可以儲存到硬碟上。

    3) Method:對於業務委託類的每個方法,現在Proxy類裡面都不用靜態顯示出來

    4) InvocationHandler: 這個類在業務委託類執行時,會先呼叫invoke方法。invoke方法再執行相應的代理操作,可以實現對業務方法的再包裝

    5 CGLib 簡介

          JDK的動態代理機制只能代理實現了介面的類,而不能實現介面的類就不能實現JDK的動態代理,cglib是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現增強,但因為採用的是繼承,所以不能對final修飾的類進行代理。 
示例 

   業務類:

[java] view plain copy

  1. package net.battier.dao;  
  2.   
  3. public interface BookFacade {  
  4.     public void addBook();  
  5. }  
 
  1. package net.battier.dao;

  2.  
  3. public interface BookFacade {

  4. public void addBook();

  5. }

   

 

 

[java] view plain copy

  1. package net.battier.dao.impl;  
  2.   
  3. /** 
  4.  * 這個是沒有實現介面的實現類 
  5.  *  
  6.  * @author student 
  7.  *  
  8.  */  
  9. public class BookFacadeImpl1 {  
  10.     public void addBook() {  
  11.         System.out.println("增加圖書的普通方法...");  
  12.     }  
  13. }  
 
  1. package net.battier.dao.impl;

  2.  
  3. /**

  4. * 這個是沒有實現介面的實現類

  5. *

  6. * @author student

  7. *

  8. */

  9. public class BookFacadeImpl1 {

  10. public void addBook() {

  11. System.out.println("增加圖書的普通方法...");

  12. }

  13. }

  14.  

  代理:

 

   

[java] view plain copy

  1. package net.battier.proxy;  
  2.   
  3. import java.lang.reflect.Method;  
  4.   
  5. import net.sf.cglib.proxy.Enhancer;  
  6. import net.sf.cglib.proxy.MethodInterceptor;  
  7. import net.sf.cglib.proxy.MethodProxy;  
  8.   
  9. /** 
  10.  * 使用cglib動態代理 
  11.  *  
  12.  * @author student 
  13.  *  
  14.  */  
  15. public class BookFacadeCglib implements MethodInterceptor {  
  16.     private Object target;  
  17.   
  18.     /** 
  19.      * 建立代理物件 
  20.      *  
  21.      * @param target 
  22.      * @return 
  23.      */  
  24.     public Object getInstance(Object target) {  
  25.         this.target = target;  
  26.         Enhancer enhancer = new Enhancer();  
  27.         enhancer.setSuperclass(this.target.getClass());  
  28.         // 回撥方法  
  29.         enhancer.setCallback(this);  
  30.         // 建立代理物件  
  31.         return enhancer.create();  
  32.     }  
  33.   
  34.     @Override  
  35.     // 回撥方法  
  36.     public Object intercept(Object obj, Method method, Object[] args,  
  37.             MethodProxy proxy) throws Throwable {  
  38.         System.out.println("事物開始");  
  39.         proxy.invokeSuper(obj, args);  
  40.         System.out.println("事物結束");  
  41.         return null;  
  42.   
  43.   
  44.     }  
  45.   
  46. }  
 
  1. package net.battier.proxy;

  2.  
  3. import java.lang.reflect.Method;

  4.  
  5. import net.sf.cglib.proxy.Enhancer;

  6. import net.sf.cglib.proxy.MethodInterceptor;

  7. import net.sf.cglib.proxy.MethodProxy;

  8.  
  9. /**

  10. * 使用cglib動態代理

  11. *

  12. * @author student

  13. *

  14. */

  15. public class BookFacadeCglib implements MethodInterceptor {

  16. private Object target;

  17.  
  18. /**

  19. * 建立代理物件

  20. *

  21. * @param target

  22. * @return

  23. */

  24. public Object getInstance(Object target) {

  25. this.target = target;

  26. Enhancer enhancer = new Enhancer();

  27. enhancer.setSuperclass(this.target.getClass());

  28. // 回撥方法

  29. enhancer.setCallback(this);

  30. // 建立代理物件

  31. return enhancer.create();

  32. }

  33.  
  34. @Override

  35. // 回撥方法

  36. public Object intercept(Object obj, Method method, Object[] args,

  37. MethodProxy proxy) throws Throwable {

  38. System.out.println("事物開始");

  39. proxy.invokeSuper(obj, args);

  40. System.out.println("事物結束");

  41. return null;

  42.  
  43.  
  44. }

  45.  
  46. }

  測試;

 

   

[java] view plain copy

  1. package net.battier.test;  
  2.   
  3. import net.battier.dao.impl.BookFacadeImpl1;  
  4. import net.battier.proxy.BookFacadeCglib;  
  5.   
  6. public class TestCglib {  
  7.       
  8.     public static void main(String[] args) {  
  9.         BookFacadeCglib cglib=new BookFacadeCglib();  
  10.         BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());  
  11.         bookCglib.addBook();  
  12.     }  
  13. }  
 
  1. package net.battier.test;

  2.  
  3. import net.battier.dao.impl.BookFacadeImpl1;

  4. import net.battier.proxy.BookFacadeCglib;

  5.  
  6. public class TestCglib {

  7.  
  8. public static void main(String[] args) {

  9. BookFacadeCglib cglib=new BookFacadeCglib();

  10. BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());

  11. bookCglib.addBook();

  12. }

  13. }