欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java動態(tài)代理實現(xiàn)_動力節(jié)點(diǎn)Java學(xué)院整理

 更新時間:2017年08月03日 10:20:56   作者:liuwei  
動態(tài)代理作為代理模式的一種擴(kuò)展形式,廣泛應(yīng)用于框架(尤其是基于AOP的框架)的設(shè)計與開發(fā),本文將通過實例來講解Java動態(tài)代理的實現(xiàn)過程

動態(tài)代理作為代理模式的一種擴(kuò)展形式,廣泛應(yīng)用于框架(尤其是基于AOP的框架)的設(shè)計與開發(fā),本文將通過實例來講解Java動態(tài)代理的實現(xiàn)過程。

通常情況下,代理模式中的每一個代理類在編譯之后都會生成一個class文件,代理類所實現(xiàn)的接口和所代理的方法都被固定,這種代理被稱之為靜態(tài)代理(Static Proxy)。那么有沒有一種機(jī)制能夠讓系統(tǒng)在運(yùn)行時動態(tài)創(chuàng)建代理類?答案就是本文將要介紹的動態(tài)代理(Dynamic Proxy)。動態(tài)代理是一種較為高級的代理模式,它在事務(wù)管理、AOP(Aspect-OrientedProgramming,面向方面編程)等領(lǐng)域都發(fā)揮了重要的作用。

在傳統(tǒng)的代理模式中,客戶端通過Proxy類調(diào)用RealSubject類的request()方法,同時還可以在代理類中封裝其他方法(如preRequest()和postRequest()等)。如果按照這種方法使用代理模式,那么代理類和真實主題類都應(yīng)該是事先已經(jīng)存在的,代理類的接口和所代理方法都已明確指定,如果需要為不同的真實主題類提供代理類或者代理一個真實主題類中的不同方法,都需要增加新的代理類,這將導(dǎo)致系統(tǒng)中的類個數(shù)急劇增加,因此需要想辦法減少系統(tǒng)中類的個數(shù)。動態(tài)代理可以讓系統(tǒng)能夠根據(jù)實際需要來動態(tài)創(chuàng)建代理類,讓同一個代理類能夠代理多個不同的真實主題類而且可以代理不同的方法。

從JDK 1.3開始,Java語言提供了對動態(tài)代理的支持,Java語言實現(xiàn)動態(tài)代理時需要用到位于java.lang.reflect包中的一些類,現(xiàn)簡要說明如下:

 (1) Proxy類

 Proxy類提供了用于創(chuàng)建動態(tài)代理類和實例對象的方法,它是所創(chuàng)建的動態(tài)代理類的父類,它最常用的方法如下:

  • public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces):該方法用于返回一個Class類型的代理類,在參數(shù)中需要提供類加載器并需要指定代理的接口數(shù)組(與真實主題類的接口列表一致)。
  • public static Object newProxyInstance(ClassLoader loader, Class<?>[]interfaces, InvocationHandler h):該方法用于返回一個動態(tài)創(chuàng)建的代理類的實例,方法中第一個參數(shù)loader表示代理類的類加載器,第二個參數(shù)interfaces表示代理類所實現(xiàn)的接口列表(與真實主題類的接口列表一致),第三個參數(shù)h表示所指派的調(diào)用處理程序類。

 (2) InvocationHandler接口

InvocationHandler接口是代理處理程序類的實現(xiàn)接口,該接口作為代理實例的調(diào)用處理者的公共父類,每一個代理類的實例都可以提供一個相關(guān)的具體調(diào)用處理者(InvocationHandler接口的子類)。在該接口中聲明了如下方法:

public Object invoke(Objectproxy, Method method, Object[] args):該方法用于處理對代理類實例的方法調(diào)用并返回相應(yīng)的結(jié)果,當(dāng)一個代理實例中的業(yè)務(wù)方法被調(diào)用時將自動調(diào)用該方法。invoke()方法包含三個參數(shù),其中第一個參數(shù)proxy表示代理類的實例,第二個參數(shù)method表示需要代理的方法,第三個參數(shù)args表示代理方法的參數(shù)數(shù)組。

動態(tài)代理類需要在運(yùn)行時指定所代理真實主題類的接口,客戶端在調(diào)用動態(tài)代理對象的方法時,調(diào)用請求會將請求自動轉(zhuǎn)發(fā)給InvocationHandler對象的invoke()方法,由invoke()方法來實現(xiàn)對請求的統(tǒng)一處理

下面通過一個簡單實例來學(xué)習(xí)如何使用動態(tài)代理模式:

Sunny軟件公司欲為公司OA系統(tǒng)數(shù)據(jù)訪問層DAO增加方法調(diào)用日志,記錄每一個方法被調(diào)用的時間和調(diào)用結(jié)果,現(xiàn)使用動態(tài)代理進(jìn)行設(shè)計和實現(xiàn)。

本實例完整代碼如下所示:

import java.lang.reflect.Proxy; 
import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 
import java.util.Calendar; 
import java.util.GregorianCalendar; 
 
//抽象UserDAO:抽象主題角色 
interface AbstractUserDAO { 
  public Boolean findUserById(String userId); 
} 
 
//抽象DocumentDAO:抽象主題角色 
interface AbstractDocumentDAO { 
  public Boolean deleteDocumentById(String documentId); 
} 
 
//具體UserDAO類:真實主題角色 
class UserDAO implements AbstractUserDAO { 
  public Boolean findUserById(String userId) { 
    if (userId.equalsIgnoreCase("張無忌")) { 
      System.out.println("查詢ID為" + userId + "的用戶信息成功!"); 
      return true; 
    } 
    else { 
      System.out.println("查詢ID為" + userId + "的用戶信息失??!"); 
      return false; 
    } 
  } 
} 
 
//具體DocumentDAO類:真實主題角色 
class DocumentDAO implements AbstractDocumentDAO { 
  public Boolean deleteDocumentById(String documentId) { 
    if (documentId.equalsIgnoreCase("D001")) { 
      System.out.println("刪除ID為" + documentId + "的文檔信息成功!"); 
      return true; 
    } 
    else { 
      System.out.println("刪除ID為" + documentId + "的文檔信息失??!"); 
      return false; 
    } 
  } 
} 
 
//自定義請求處理程序類 
class DAOLogHandler implements InvocationHandler { 
  private Calendar calendar; 
  private Object object; 
   
  public DAOLogHandler() {   
  } 
   
  //自定義有參構(gòu)造函數(shù),用于注入一個需要提供代理的真實主題對象 
  public DAOLogHandler(Object object) { 
    this.object = object; 
  } 
   
  //實現(xiàn)invoke()方法,調(diào)用在真實主題類中定義的方法 
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
    beforeInvoke(); 
    Object result = method.invoke(object, args); //轉(zhuǎn)發(fā)調(diào)用 
    afterInvoke(); 
    return null; 
  } 
 
  //記錄方法調(diào)用時間 
  public void beforeInvoke(){ 
    calendar = new GregorianCalendar(); 
    int hour = calendar.get(Calendar.HOUR_OF_DAY); 
    int minute = calendar.get(Calendar.MINUTE); 
    int second = calendar.get(Calendar.SECOND); 
    String time = hour + ":" + minute + ":" + second; 
    System.out.println("調(diào)用時間:" + time); 
  } 
 
  public void afterInvoke(){ 
    System.out.println("方法調(diào)用結(jié)束!" ); 
  } 
} 

編寫如下客戶端測試代碼:

class Client { 
  public static void main(String args[]) { 
    InvocationHandler handler = null; 
     
    AbstractUserDAO userDAO = new UserDAO(); 
    handler = new DAOLogHandler(userDAO); 
    AbstractUserDAO proxy = null; 
    //動態(tài)創(chuàng)建代理對象,用于代理一個AbstractUserDAO類型的真實主題對象 
    proxy = (AbstractUserDAO)Proxy.newProxyInstance(AbstractUserDAO. class.getClassLoader(), new Class[]{AbstractUserDAO.class}, handler); 
    proxy.findUserById("張無忌"); //調(diào)用代理對象的業(yè)務(wù)方法 
   
    System.out.println("------------------------------"); 
   
    AbstractDocumentDAO docDAO = new DocumentDAO(); 
    handler = new DAOLogHandler(docDAO); 
    AbstractDocumentDAO proxy_new = null; 
//動態(tài)創(chuàng)建代理對象,用于代理一個AbstractDocumentDAO類型的真實主題對象 
    proxy_new = (AbstractDocumentDAO)Proxy.newProxyInstance(Abstract DocumentDAO.class.getClassLoader(), new Class[]{AbstractDocumentDAO.class}, handler); 
    proxy_new.deleteDocumentById("D002"); //調(diào)用代理對象的業(yè)務(wù)方法 
  }  
} 

編譯并運(yùn)行程序,輸出結(jié)果如下:

調(diào)用時間:13:47:14
查詢ID為張無忌的用戶信息成功!
方法調(diào)用結(jié)束!
------------------------------
調(diào)用時間:13:47:14
刪除ID為D002的文檔信息失??!
方法調(diào)用結(jié)束!

通過使用動態(tài)代理,我們可以實現(xiàn)對多個真實主題類的統(tǒng)一代理和集中控制。

注:JDK中提供的動態(tài)代理只能代理一個或多個接口,如果需要動態(tài)代理具體類或抽象類,可以使用CGLib(Code Generation Library)等工具,CGLib是一個功能較為強(qiáng)大、性能和質(zhì)量也較好的代碼生成包,在許多AOP框架中都得以廣泛應(yīng)用,大家可以自行查閱相關(guān)資料來學(xué)習(xí)CGLib。

相關(guān)文章

  • Spring 中優(yōu)雅的獲取泛型信息的方法

    Spring 中優(yōu)雅的獲取泛型信息的方法

    這篇文章主要介紹了Spring 中優(yōu)雅的獲取泛型信息的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • 實例分析Try {} Catch{} 作用

    實例分析Try {} Catch{} 作用

    本文是通過一個簡單的實例,向大家介紹了Try {} Catch{}的意義和作用,非常的實用,有需要的小伙伴可以參考下。
    2015-10-10
  • mybatis清除一級緩存的幾種方式

    mybatis清除一級緩存的幾種方式

    這篇文章主要介紹了mybatis清除一級緩存的幾種方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • Java實現(xiàn)的漢語拼音工具類完整實例

    Java實現(xiàn)的漢語拼音工具類完整實例

    這篇文章主要介紹了Java實現(xiàn)的漢語拼音工具類,結(jié)合完整實例形式分析了java基于pinyin4j包實現(xiàn)編碼轉(zhuǎn)換的相關(guān)操作技巧,需要的朋友可以參考下
    2017-11-11
  • java中String與StringBuilder的區(qū)別

    java中String與StringBuilder的區(qū)別

    本篇文章介紹了,java中String與StringBuilder的區(qū)別。需要的朋友參考下
    2013-04-04
  • SpringBoot在項目中訪問靜態(tài)資源步驟分析

    SpringBoot在項目中訪問靜態(tài)資源步驟分析

    今天在玩SpringBoot的demo的時候,放了張圖片在resources目錄下,啟動區(qū)訪問的時候,突然好奇是識別哪些文件夾來展示靜態(tài)資源的, 為什么有時候放的文件夾不能顯示,有的卻可以
    2023-01-01
  • java使用定時器實現(xiàn)監(jiān)聽數(shù)據(jù)變化

    java使用定時器實現(xiàn)監(jiān)聽數(shù)據(jù)變化

    這篇文章主要為大家詳細(xì)介紹了Java如何使用定時器監(jiān)聽數(shù)據(jù)變化,當(dāng)滿足某個條件時(例如沒有數(shù)據(jù)更新)自動執(zhí)行某項任務(wù),有興趣的可以了解下
    2023-11-11
  • springcloud微服務(wù)基于redis集群的單點(diǎn)登錄實現(xiàn)解析

    springcloud微服務(wù)基于redis集群的單點(diǎn)登錄實現(xiàn)解析

    這篇文章主要介紹了springcloud微服務(wù)基于redis集群的單點(diǎn)登錄實現(xiàn)解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-09-09
  • Java開發(fā)人員最常犯的5個錯誤總結(jié)

    Java開發(fā)人員最常犯的5個錯誤總結(jié)

    作為一名java開發(fā)程序員,不知道大家有沒有遇到過一些匪夷所思的bug。這些錯誤通常需要您幾個小時才能解決。今天,小編總結(jié)一些常見的編碼錯誤,然后給出解決方案。希望大家在日常編碼中能夠避免這樣的問題
    2022-12-12
  • Java集合功能與用法實例詳解

    Java集合功能與用法實例詳解

    這篇文章主要介紹了Java集合功能與用法,結(jié)合實例形式詳細(xì)分析了java集合的基本概念、功能、原理、操作技巧與使用注意事項,需要的朋友可以參考下
    2020-04-04

最新評論