[摘錄]從代理機制初探AOP

          摘錄地址:http://www.javaworld.com.tw/jute/post/print?bid=5&id=81236

          1. 從代理機制初探 AOP? Copy to clipboard

          Posted by: caterpillar

          Posted on: 2004-11-24 11:10

          ?

          ?

          AOP OOP 我覺得 AOP 觀念其實不難,只是很容易被中文混淆, Aspect 在牛津字典中是這么解釋的: particular part or feature of sth being considered.

          ?

          Aspect 中文直譯通常作「方面」,方面在中文通常作「角度」解譯,我們常說「就這個方面來看」,其意是「就這個角度來看」,但在上面的英文解釋中, aspect part 的意義,中文來說是「就這個部份來看」,「我」覺得 Aspect 在中文上應是取這個意思。

          ?

          例如一個動作在執行過程中的某個「部份」是 AOP 所關注的,這個部份切入了執行過程,但本身不屬于執行的最終目的,例如事務管理,執行的目的可能是儲存數據,但事務管理切入了這個過程, AOP 關注于這個「切入面」,希望將其設計為通用,不介入對象設計的一個通用組件。

          ?

          AOP 「我」比較接受的一個中文翻譯是「切面導向」,這可以免除「方面」兩字較具「表面」的意義, Aspect 是一個「面」沒錯,但是具有橫切入過程的感覺。。。。。

          ?

          總之,先看看下面的文章,我想應該比較了解吧。。。。。

          ?

          ==================================

          ?

          AOP 的全名是 Aspect-oriented Programming Aspect 是程序設計時一個新的中心, AOP 并不取代 OOP ,兩者各有各的角色,將職責各自分配自 Object Aspect ,會使得程序中各個組件的角色更為清楚。

          ?

          這邊先不直接探討 AOP ,我們先從一個簡單常見的例子來看看一個議題,這個例子是記錄( log )動作,程序中很常需要為某些動作或事件作下記錄,以便在事后檢視或是作為除錯時的信息,一個最簡單的例子如下:

          import java.util.logging.*;

          ???????????????????????????????????????????????????????????????????????????????

          public class HelloSpeaker {

          ??? private Logger logger = Logger.getLogger(this.getClass().getName());

          ???????????????????????????????????????????????????????????????????????????????

          ?? ?public void hello(String name) {

          ??????? logger.log(Level.INFO, "hello method starts....");

          ???????????????????????????????????????????????????????????????????????????????

          ??????? System.out.println("Hello, " + name);

          ???????????????????????????????????????????????????????????????????????????????

          ??????? logger.log(Level.INFO, "hello method ends....");

          ??? }

          }

          ?

          ?

          HelloSpeaker 在執行 hello() 方法時,我們希望能記錄該方法已經執行及結束,最簡單的作法就是如上在執行的前后加上記錄動作,然而 Logger 介入了 HelloSpeaker 中,記錄這個動作并不屬于 HelloSpeaker ,這使得 HelloSpeaker 的職責加重。

          ?

          想想如果程序中這種記錄的動作到處都有需求,上面這種寫法勢必造成我們必須復制記錄動作的程序代碼,使得維護記錄動作的困難度加大。如果不只有記錄動作,有一些非對象本身職責的相關動作也混入了對象之中(例如權限檢查、事務管理等等),會使得對象的負擔更形加重,甚至混淆了對象的職責,對象本身的職責所占的程序代碼,或許遠小于這些與對象職責不相關動作的程序代碼。

          ?

          怎么辦,用下面的方法或許好一些,我們先定義一個接口,然后實作該接口:

          public interface IHello {

          ??? public void hello(String name);

          }

          ?

          public class HelloSpeaker implements IHello {

          ??? public void hello(String name) {

          ??????? System.out.println("Hello, " + name);

          ??? }

          }

          ?

          ?

          接下來是重點了,我們實作一個代理對象 HelloProxy

          import java.util.logging.*;

          ???????????????????????????????????????????????????????????????????????????????

          public class HelloProxy implements IHello {

          ??? private Logger logger = Logger.getLogger(this.getClass().getName());

          ??? private IHello helloObject;

          ???????????????????????????????????????????????????????????????????????????????

          ??? public HelloProxy(IHello helloObject) {

          ??????? this.helloObject = helloObject;

          ??? }

          ???????????????????????????????????????????????????????????????????????????????

          ? ?? public void hello(String name) {

          ??????? logger.log(Level.INFO, "hello method starts....");

          ???????????????????????????????????????????????????????????????????????????????

          ??????? helloObject.hello(name);

          ?????????????????????????????????????????????? ?????????????????????????????????

          ??????? logger.log(Level.INFO, "hello method ends....");

          ??? }

          }

          ?

          執行時可以如此:

          IHello helloProxy = new HelloProxy(new HelloSpeaker());

          helloProxy.hello("Justin");

          ?

          ?

          代理對象 HelloProxy 將代理真正的 HelloSpeaker 來執行 hello() ,并在其前后加上記錄的動作,這使得我們的 HelloSpeaker 在撰寫時不必介入記錄動作, HelloSpeaker 可以專心于它的職責。

          ?

          這是靜態代理的基本范例,然而如您所看到的,代理對象的一個接口只服務于一種類型的對象,而且如果要代理的方法很多,我們勢必要為每個方法進行代理,靜態代理在程序規模稍大時就必定無法勝任。

          ?

          Java JDK 1.3 之后加入協助開發動態代理功能的類別,我們不必為特定對象與方法撰寫特定的代理,使用動態代理,可以使得一個 handler 服務于各個對象,首先,一個 handler 必須實現 java.lang.reflect.InvocationHandler

          import java.util.logging.*;

          import java.lang.reflect.*;

          ????????????????????????????????????????????????????????????????????? ?????????????????

          public class LogHandler implements InvocationHandler {

          ??? private Logger logger = Logger.getLogger(this.getClass().getName());

          ??? private Object delegate;

          ???????????????????????????????????????????????????????????????????????????????? ??????

          ??? public Object bind(Object delegate) {

          ??????? this.delegate = delegate;

          ??????? return Proxy.newProxyInstance(

          ?????????????????????????? delegate.getClass().getClassLoader(),

          ?????????????????????????? delegate.getClass().getInterfaces(),

          ???? ??????????????????????this);

          ??? }

          ??????????????????????????????????????????????????????????????????????????????????????

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

          ??????????????? throws Throwable {

          ??????? Object result = null;

          ??????? try {

          ??????????? logger.log(Level.INFO, "method stats..." + method);

          ??????????? result = method.invoke(delegate, args);

          ??????????? logger.log(Level.INFO, "method ends..." + method);

          ??????? } catch (Exception e){

          ??????????? logger.log(Level.INFO, e.toString());

          ??????? }

          ??????? return result;

          ??? }

          }

          ?

          InvocationHandler invoke() 方法會傳入被代理對象的方法名稱與執行參數實際上要執行的方法交由 method.invoke() ,并在其前后加上記錄動作, method.invoke() 傳回的對象是實際方法執行過后的回傳結果。

          ?

          動態代理必須宣告接口,實作該接口,例如:

          public interface IHello {

          ??? public void hello(String name);

          }

          ?

          public class HelloSpeaker implements IHello {

          ??? public void hello(String name) {

          ??????? System.out.println("Hello, " + name);

          ??? }

          }

          ?

          ?

          java.lang.reflect.Proxy newProxyInstance() 依要代理的對象、接口與 handler 產生一個代理對象,我們可以使用下面的方法來執行程序:

          LogHandler logHandler? = new LogHandler();

          IHello helloProxy = (IHello) logHandler.bind(new HelloSpeaker());

          helloProxy.hello("Justin");

          ?

          ?

          LogHandler 不在服務于特定對象與接口,而 HelloSpeaker 也不用插入任何有關于記錄的動作,它不用意識到記錄動作的存在。

          ?

          講了半天,我們回到 AOP 的議題上,這個例子與 AOP 有何關系?

          ?

          如上面的例子中示范的, HelloSpeaker 本來必須插入記錄動作,這使得 HelloSpeaker 的職責加重,并混淆其原來的角色,為此,我們使用代理將記錄的動作提取出來,以厘清記錄動作與 HelloSpeaker 的職責與角色。

          ?

          在這里,記錄這個動作是我們所關注的, AOP 中的 Aspect 所指的就是像記錄這類的動作,我們將這些動作(或特定職責)視為關注的中心,將其設計為通用、不介入特定對象、職責清楚的組件,這就是所謂的「 Aspect 導向」(比較好的一個中文翻法是「切面導向」,下一個主題再說明),就如同「對象導向」一樣,每個對象僅代表一個實際的個體,將對象視為關注的中心,將其設計為通用、職責清楚的組件。

          ?

          這邊先以代理機制作為一個開端初步探討 AOP ,如您所看到的, AOP OOP 并不抵觸,兩者的合作使得程序更為清晰, Object Aspect 職責不互相混淆,而且都更具重用性,下一個主題我們再來深入 AOP 的一些細節。

          ?



          歡迎大家訪問我的個人網站 萌萌的IT人

          posted on 2006-04-24 11:16 見酒就暈 閱讀(121) 評論(0)  編輯  收藏 所屬分類: J2EE文章

          <2025年6月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          導航

          統計

          常用鏈接

          留言簿(3)

          我參與的團隊

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          收藏夾

          BLOG

          FRIENDS

          LIFE

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 涿州市| 林西县| 长治市| 丽水市| 怀仁县| 黄石市| 郎溪县| 新邵县| 富宁县| 深泽县| 时尚| 兴城市| 连江县| 许昌县| 邵东县| 鹰潭市| 含山县| 保德县| 隆德县| 青神县| 益阳市| 洛宁县| 潢川县| 邳州市| 额敏县| 防城港市| 龙江县| 碌曲县| 南城县| 灵台县| 金乡县| 连山| 乐平市| 元阳县| 房产| 巴马| 彭阳县| 乌鲁木齐市| 喜德县| 水城县| 丁青县|