亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

Java理論與實踐:用動態代理進行修飾

2019-11-18 13:31:38
字體:
來源:轉載
供稿:網友

  動態代理為實現許多常見設計模式(包括 Facade、Bridge、Interceptor、Decorator、PRoxy(包括遠程和虛擬代理)和 Adapter 模式)提供了替代的動態機制。雖然這些模式不使用動態代理,只用普通的類就能夠實現,但是在許多情況下,動態代理方式更方便、更緊湊,可以清除許多手寫或生成的類。
  
  Proxy 模式
  
  Proxy 模式中要創建“stub”或“surrogate”對象,它們的目的是接受請求并把請求轉發到實際執行工作的其他對象。遠程方法調用(RMI)利用 Proxy 模式,使得在其他 JVM 中執行的對象就像本地對象一樣;企業 javaBeans (EJB)利用 Proxy 模式添加遠程調用、安全性和事務分界;而 JAX-RPC Web 服務則用 Proxy 模式讓遠程服務表現得像本地對象一樣。在每一種情況中,潛在的遠程對象的行為是由接口定義的,而接口本質上接受多種實現。調用者(在大多數情況下)不能區分出它們只是持有一個對 stub 而不是實際對象的引用,因為二者實現了相同的接口;stub 的工作是查找實際的對象、封送參數、把參數發送給實際對象、解除封送返回值、把返回值返回給調用者。代理可以用來提供遠程控制(就像在 RMI、EJB 和 JAX-RPC 中那樣),用安全性策略包裝對象(EJB)、為昂貴的對象(EJB 實體 Bean)提供惰性裝入,或者添加檢測工具(例如日志記錄)。
  
  在 5.0 以前的 JDK 中,RMI stub(以及它對等的 skeleton)是在編譯時由 RMI 編譯器(rmic)生成的類,RMI 編譯器是 JDK 工具集的一部分。對于每個遠程接口,都會生成一個 stub(代理)類,它代表遠程對象,還生成一個 skeleton 對象,它在遠程 JVM 中做與 stub 相反的工作 ―― 解除封送參數并調用實際的對象。類似地,用于 Web 服務的 JAX-RPC 工具也為遠程 Web 服務生成代理類,從而使遠程 Web 服務看起來就像本地對象一樣。
  
  不管 stub 類是以源代碼還是以字節碼生成的,代碼生成仍然會向編譯過程添加一些額外步驟,而且因為命名相似的類的泛濫,會帶來意義模糊的可能性。另一方面,動態代理機制支持在編譯時沒有生成 stub 類的情況下,在運行時創建代理對象。在 JDK 5.0 及以后版本中,RMI 工具使用動態代理代替了生成的 stub,結果 RMI 變得更輕易使用。許多 J2EE 容器也使用動態代理來實現 EJB。EJB 技術嚴重地依靠使用攔截(interception)來實現安全性和事務分界;動態代理為接口上調用的所有方法提供了集中的控制流程路徑。
  
  動態代理機制
  
  動態代理機制的核心是 InvocationHandler 接口,如清單 1 所示。調用句柄的工作是代表動態代理實際執行所請求的方法調用。傳遞給調用句柄一個 Method 對象(從 java.lang.reflect 包),參數列表則傳遞給方法;在最簡單的情況下,可能僅僅是調用反射性的方法 Method.invoke() 并返回結果。
  
  清單 1. InvocationHandler 接口
  
  public interface InvocationHandler {
  Object invoke(Object proxy, Method method, Object[] args)
  throws Throwable;
  }
  
  每個代理都有一個與之關聯的調用句柄,只要代理的方法被調用時就會調用該句柄。根據通用的設計原則:接口定義類型、類定義實現,代理對象可以實現一個或多個接口,但是不能實現類。因為代理類沒有可以訪問的名稱,它們不能有構造函數,所以它們必須由工廠創建。清單 2 顯示了動態代理的最簡單的可能實現,它實現 Set 接口并把所有 Set 方法(以及所有 Object 方法)分派給封裝的 Set 實例。
  
  清單 2. 包裝 Set 的簡單的動態代理
  
  public class SetProxyFactory {
  
  public static Set getSetProxy(final Set s) {
  return (Set) Proxy.newProxyInstance
  (s.getClass().getClassLoader(),
  new Class[] { Set.class },
  new InvocationHandler() {
  public Object invoke(Object proxy, Method method,
  Object[] args) throws Throwable {
  return method.invoke(s, args);
  }
  });
  }
  }
  
  SetProxyFactory 類包含一個靜態工廠方法 getSetProxy(),它返回一個實現了 Set 的動態代理。代理對象實際實現 Set ―― 調用者無法區分(除非通過反射)返回的對象是動態代理。SetProxyFactory 返回的代理只做一件事,把方法分派給傳遞給工廠方法的 Set 實例。雖然反射代碼通常比較難讀,但是這里的內容很少,跟上控制流程并不難 ―― 只要某個方法在 Set 代理上被調用,它就被分派給調用句柄,調用句柄只是反射地調用底層包裝的對象上的目標方法。當然,絕對什么都不做的代理可能有點傻,是不是呢?
  
  什么都不做的適配器
  
  對于像 SetProxyFactory 這樣什么都不做的包裝器來說,實際有個很好的應用 ―― 可以用它安全地把對象引用的范圍縮小到特定接口(或接口集)上,方式是,調用者不能提升引用的類型,使得可以更安全地把對象引用傳遞給不受信任的代碼(例如插件或回調)。清單 3 包含一組類定義,實現了典型的回調場景。從中會看到動態代理可以更方便地替代通常用手工(或用 IDE 提供的代碼生成向導)實現的 Adapter 模式。
  
  清單 3. 典型的回調場景
  
  public interface ServiceCallback {
  public void doCallback();
  }
  
  public interface Service {
  public void serviceMethod(ServiceCallback callback);
  }
  
  public class ServiceConsumer implements ServiceCallback {
  private Service service;
  
  ...
  public void someMethod() {
  ...
  service.serviceMethod(this);
  }
  }
  
  ServiceConsumer 類實現了 ServiceCallback(這通常是支持回調的一個方便途徑)并把 this 引用傳遞給 serviceMethod() 作為回調引用。這種方法的問題是沒有機制可以阻止 Service 實現把 ServiceCallback 提升為 ServiceConsumer,并調用 ServiceConsumer 不希望 Service 調用的方法。有時對這個風險并不關心 ―― 但有時卻關心。假如關心,那么可以把回調對象作為內部類,或者編寫一個什么都不做的適配器類(請參閱清單 4 中的 ServiceCallbackAdapter)并用 ServiceCallbackAdapter 包裝 ServiceConsumer。ServiceCallbackAdapter 防止 Service 把 ServiceCallback 提升為 ServiceConsumer。
  
  清單 4. 用于安全地把對象限制在一個接口上以便不被惡意代碼不能的適配器類
  
  public class ServiceCallbackAdapter implements ServiceCallback {
  private final ServiceCallback cb;
  
  public ServiceCallbackAdapter(ServiceCallback cb) {
  this.cb = cb;
  }
  
  public void doCallback() {
  cb.doCallback();
  }
  }
  
  編寫 ServiceCallbackAdapter 這樣的適配器類簡單卻乏味。必須為包裝的接口中的每個方法編寫重定向類。在 ServiceCallback 的示例中,只有一個需要實現的方法,但是某些接口,例如 Collections 或 JDBC 接口,則包含許多方法?,F代的 IDE 提供了“Delegate Methods”向導,降低了編寫適配器類的工作量,但是仍然必須為每個想要包裝的接口編寫一個適配器類,而且對于只包含生成的代碼的類,也有一些讓人不滿足的地方。看起來應當有一種方式可以更緊湊地表示“什么也不做的限制適配器模式”。
  
  通用適配器類
  
  清單 2 中的 SetProxyFactory 類當然比用于 Set 的等價的適配器類更緊湊,但是它仍然只適用于一個接口:Set。但是通過使用泛型,可以輕易地創建通用的代理工廠,由它為任何接口做同樣的工作,如清單 5 所示。它幾乎與 SetProxyFactory 相同,但是可以適用于任何接口?,F在再也不用編寫限制適配器類了!假如想創建代理對象安全地把對象限制在接口 T,只要調用 getProxy(T.class,object) 就可以了,不需要一堆適配器類的額外累贅。
  
  清單 5. 通用的限制適配器工廠類
  
  public class GenericProxyFactory {
  
  public static<T> T getProxy(Class<T> intf,
  final T obj) {
  return (T)
  Proxy.newProxyInstance(obj.getClass().getClassLoader(),
  new Class[] { intf },
  new InvocationHandler() {
  public Object invoke(Object proxy, Method method,
  Object[] args) throws Throwable {
  return method.invoke(obj, args);
  }
  });
  }
  }
  
  動態代理作為 Decorator
  
  當然,動態代理工具能做的,遠不僅僅是把對象類型限制在特定接口上。從 清單 2 和 清單 5 中簡單的限制適配器到 Decorator 模式,是一個小的飛躍,在 Decorator 模式中,代理用額外的功能(例如安全檢測或日志記錄)包裝調用。清單 6 顯示了一個日志 InvocationHandler,它在調用目標對象上的方法之外,還寫入一條日志信息,顯示被調用的方法、傳遞的參數,以及返回值。除了反射性的 invoke() 調用之外,這里的全部代碼只是生成調試信息的一部分 ―― 還不是太多。代理工廠方法的代碼幾乎與 GenericProxyFactory 相同,區別在于它使用的是 LoggingInvocationHandler 而不是匿名的調用句柄。
  
  清單 6. 基于代理的 Decorator,為每個方法調用生成調試日志
  
  private static class LoggingInvocationHandler<T>
  implements InvocationHandler {
  final T underlying;
  
  public LoggingHandler(T underlying) {
  this

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日本高清视频一区| 国产精品中文字幕在线观看| 欧美在线观看网址综合| 日韩欧美成人精品| 久久人91精品久久久久久不卡| 一区二区三区亚洲| 国产日韩一区在线| 欧美另类老女人| 亚洲精品美女视频| 欧美成人免费全部观看天天性色| 超碰日本道色综合久久综合| 激情成人中文字幕| 一区二区三区在线播放欧美| 精品视频偷偷看在线观看| 亚洲精品91美女久久久久久久| 日韩极品精品视频免费观看| 98视频在线噜噜噜国产| 国产精品一区av| 日韩精品欧美国产精品忘忧草| 亚洲精品美女在线观看播放| 国产精品久久二区| 亚洲女人天堂成人av在线| 日韩欧美亚洲范冰冰与中字| 成人国产在线视频| 欧美午夜精品伦理| 最近2019年好看中文字幕视频| 黄色精品一区二区| 亚洲欧美国产精品| 日韩免费观看视频| 日韩中文字幕视频在线观看| 精品久久久久久久久久| 精品亚洲aⅴ在线观看| 久久久久久久久久国产精品| 欧美性猛交xxxx久久久| 中国日韩欧美久久久久久久久| 国内精品伊人久久| 国产精品天天狠天天看| 亚洲国产日韩精品在线| 992tv成人免费影院| 欧美性xxxx18| 久久97精品久久久久久久不卡| 91地址最新发布| 国产99久久久欧美黑人| 中文精品99久久国产香蕉| 韩剧1988免费观看全集| 国产精品久久国产精品99gif| 亚洲影院污污.| 午夜精品国产精品大乳美女| 色99之美女主播在线视频| 欧美激情区在线播放| 国产在线久久久| 欧美日韩国产精品一区二区三区四区| 91视频免费网站| 精品国内亚洲在观看18黄| 久久精品亚洲一区| 久久影院中文字幕| 午夜精品一区二区三区av| 91av在线看| 国产精品欧美激情| 亚洲成人在线网| 91av在线免费观看| 中文字幕亚洲综合| 亚洲精品午夜精品| 国产精品视频一区二区高潮| 亚洲jizzjizz日本少妇| 韩国美女主播一区| 国产欧美精品一区二区三区介绍| 性欧美暴力猛交69hd| 97香蕉超级碰碰久久免费软件| 久久久久99精品久久久久| 久久综合伊人77777| 疯狂做受xxxx欧美肥白少妇| 亚洲女人初尝黑人巨大| 欧美激情在线观看视频| 国产精品久久久久久久久影视| 日韩精品视频在线播放| 一本色道久久综合狠狠躁篇的优点| 午夜精品三级视频福利| 国产日韩中文字幕在线| 伦理中文字幕亚洲| 菠萝蜜影院一区二区免费| 国产日韩欧美在线视频观看| 欧美黑人xxx| 亚洲欧美在线第一页| 精品亚洲一区二区三区四区五区| 理论片在线不卡免费观看| 亚洲精品日产aⅴ| 国产日韩中文字幕在线| 91tv亚洲精品香蕉国产一区7ujn| 国产日本欧美一区二区三区在线| 亚洲国产成人精品电影| 精品国偷自产在线视频99| 国产欧美精品一区二区三区-老狼| 成人激情视频小说免费下载| 久久免费视频网| 日韩欧美国产中文字幕| 日日骚久久av| 久久精品精品电影网| 欧美激情中文网| 国产精品久久久久免费a∨| 97香蕉久久夜色精品国产| 国产香蕉一区二区三区在线视频| 欧美丰满少妇xxxx| 97在线日本国产| 欧美精品成人91久久久久久久| 亚洲国产高潮在线观看| 欧美激情一区二区三级高清视频| 成人激情视频免费在线| 久久九九有精品国产23| 国产精品福利在线观看| 欧美电影免费看| 国产精欧美一区二区三区| 成人午夜在线观看| 日韩精品有码在线观看| 国产欧洲精品视频| 粗暴蹂躏中文一区二区三区| 97欧美精品一区二区三区| 日韩av中文字幕在线免费观看| 亚洲精品国偷自产在线99热| 国产丝袜视频一区| 日韩免费精品视频| 久久亚洲精品一区| 国产精品久久一| 国产精品亚洲精品| 欧美日韩在线观看视频| 欧美性猛交xxxx免费看漫画| 在线丨暗呦小u女国产精品| 欧美国产日韩一区二区在线观看| 国产精品久久久久久久久久久久久久| 国产一区av在线| 成人在线观看视频网站| 亚洲激情国产精品| 欧美一区二区三区图| 欧美激情视频网址| 久久躁狠狠躁夜夜爽| 亚洲欧美日韩中文在线| 大胆人体色综合| 中文在线资源观看视频网站免费不卡| 欧美性生交大片免网| 国内精品国产三级国产在线专| 色婷婷亚洲mv天堂mv在影片| 国产亚洲精品成人av久久ww| 97国产suv精品一区二区62| 国产日韩欧美自拍| 久久亚洲综合国产精品99麻豆精品福利| 播播国产欧美激情| 神马久久久久久| 欧美激情精品久久久久| 亚洲欧美在线免费观看| 日韩成人在线播放| 欧美精品福利视频| 日韩大陆欧美高清视频区| 最近2019中文字幕第三页视频| 久久999免费视频| 国产精品成人一区二区| 久久久久久成人精品| 日韩av电影院| 69视频在线免费观看| 亚洲免费av电影| 亚洲欧美色婷婷| 亚洲一区免费网站| 在线观看不卡av| 热99精品只有里视频精品| 人人澡人人澡人人看欧美|