在JDK
1.3之後加入了可協助開發動態代理功能的API等相關類別,您不必為特定物件與方法撰寫特定的代理物件,使用動態代理,可以使得一個處理者
(Handler)服務於各個物件,首先,一個處理者的類別設計必須實作java.lang.reflect.InvocationHandler介面,
以實例來進行說明,例如設計一個LogHandler類別:
package onlyfun.caterpillar; 主要的概念是使用Proxy.newProxyInstance()靜態方法建立一個代理物件,建立代理物件時必須告知所要代理的介面,之後您可以操作所 建立的代理物件,在每次操作時會呼叫InvocationHandler的invoke()方法,invoke()方法會傳入被代理物件的方法名稱與執行 參數,實際上要執行的方法交由method.invoke(),您在method.invoke()前後加上記錄動作,method.invoke()傳 回的物件是實際方法執行過後的回傳結果。 要實現動態代理,同樣必須定義所要代理的介面,例如:
package onlyfun.caterpillar; 然後讓實現商務邏輯的HelloSpeaker類別要實現IHello介面,例如:
package onlyfun.caterpillar; 眼尖的您或許發現到了,這跟之前 從代理機制初探 AOP 中的IHello介面、HelloSpeaker是相同的內容,在這邊撰寫出來是為了範例的完整呈現。接下來撰寫一個測試的程式,您要使用LogHandler的bind()方法來綁定被代理物件,如下所示:
package onlyfun.caterpillar; 回到AOP的議題上,這個例子與AOP有何關係? 如以上的例子中示範的,HelloSpeaker本身的職責是顯示招呼文字,卻必須插入日誌(Log)動作,這使得HelloSpeaker的職責加重,在AOP的術語來說,日誌的程式碼橫切(Cross-cutting)入HelloSpeaker的程式執行流程中,日誌這樣的動作在AOP中稱之為橫切關切點(Cross-cutting concern)。 使用代理物件將記錄等與商務邏輯無關的動作或務提取出來,設計為為一個服務物件,像是之前範例中示範的HelloProxy或是LogHandler,這樣的物件稱之為切面(Aspect)。 AOP中的Aspect所指的可以是像日誌等這類的動作或服務,您將這些動作(Cross-cutting concerns)設計為通用、不介入特定業務物件的一個職責清楚的Aspect物件,這就是所謂的Aspect-oriented programming,縮寫名詞即為AOP。 在好的設計之下,Aspect可以獨立於應用程式之外,在必要的時候,可以介入應用程式之中提供服務,而不需要相關服務的時候,又可以將這些Aspect直接從應用程式中脫離,而您的應用程式本身不需修改任何一行程式碼。 |