Aspect Oriented Programming
AOP概念
Aspect Oriented Programming(AOP)是近來較為熱門的一個話題。AOP,國內
大致譯作“面向方面編程”。
“面向方面編程”,這樣的名字并不是非常容易理解,且容易產生一些誤導。筆者不止
一次聽到類似“OOP/OOD11即將落伍,AOP是新一代軟件開發方式”這樣的發言。顯然,
發言者并沒有理解AOP的含義。
Aspect,沒錯,的確是“方面”的意思。不過,華語傳統語義中的“方面”,大多數情
況下指的是一件事情的不同維度、或者說不同角度上的特性,比如我們常說:“這件事情要
從幾個方面來看待”,往往意思是:需要從不同的角度來看待同一個事物。這里的“方面”,
指的是事務的外在特性在不同觀察角度下的體現。
而在AOP中,Aspect的含義,可能更多的理解為“切面”比較合適。所以筆者更傾向
于“面向切面編程”的譯法。
另外需要提及的是,AOP、OOP在字面上雖然非常類似,但卻是面向不同領域的兩種
設計思想。OOP(面向對象編程)針對業務處理過程的實體及其屬性和行為進行抽象封裝,
以獲得更加清晰高效的邏輯單元劃分。
而AOP則是針對業務處理過程中的切面進行提取,它所面對的是處理過程中的某個步
驟或階段,以獲得邏輯過程中各部分之間低耦合性的隔離效果。這兩種設計思想在目標上有
著本質的差異。
上面的陳述可能過于理論化,舉個簡單的例子,對于“雇員”這樣一個業務實體進行封
裝,自然是OOP/OOD的任務,我們可以為其建立一個“Employee”類,并將“雇員”相
關的屬性和行為封裝其中。而用AOP設計思想對“雇員”進行封裝將無從談起。
同樣,對于“權限檢查”這一動作片斷進行劃分,則是AOP的目標領域。而通過OOD/OOP
對一個動作進行封裝,則有點不倫不類。
換而言之,OOD/OOP面向名詞領域,AOP面向動詞領域。
AOP和OOD/OOP并不沖突,我們完全可以在一個應用系統中同時應用OOD/OOP和
AOP設計思想,通過OOD/OOP對系統中的業務對象進行建模,同時通過AOP對實體處理
過程中的階段進行隔離處理。即使不是OOD/OOP,而是在傳統的POP(面向過程編程)中,
AOP也能起到同樣的作用。
將不同階段領域加以分隔,這是否就算是AOP呢?
AOP還有另外一個重要特點:源碼組成無關性。
11 OOD = Object Oriented Design OOP = Object Oriented Programming
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
倘若應用中通過某個具體的業務邏輯類實現了獨立的權限檢查,而請求調度方法通過預
編碼調用這個權限模塊實現權限管理。那么這也不算是AOP。對于AOP組件而言,很重要
的一點就是源碼組成無關性,所謂源碼組成無關性,體現在具體設計中就是AOP組件必須
與應用代碼無關,簡單來講,就是應用代碼可以脫離AOP組件獨立編譯。
為了實現源碼組成無關性,AOP往往通過預編譯方式(如AspectJ)和運行期動態代理
模式(如Spring AOP 和JBoss AOP)實現。
稍后章節中我們會就Spring Framework中的AOP實現機制進行更加深入的探討。
下面先來看AOP中幾個比較重要的概念:
1. 切面(Aspect)
切面,對象操作過程中的截面。這可能是AOP中最關鍵的一個術語。
我們首先來看一個應用開發中常見的切面:用戶權限檢查。大概只要是完整的應用,都
少不了用戶權限檢查這個模塊,不同身份的用戶可以做什么,不可以做什么,均由這個模塊
加以判定。而這個模塊調用的位置通常也比較固定:用戶發起請求之后,執行業務邏輯之前。
針對權限檢查這一模塊進行分離,我們就得到了一個切面:
切面意義何在?
首先根據上例,假設我們實現了一個通用的權限檢查模塊,那么就可以在這層切面上進
行統一的集中式權限管理。而業務邏輯組件則無需關心權限方面的問題。也就是說,通過切
面,我們可以將系統中各個不同層次上的問題隔離開來,實現統一集約式處理。各切面只需
集中于自己領域內的邏輯實現。
這一方面使得開發邏輯更加清晰,專業化分工更加易于進行;另一方面,由于切面的隔
離,降低了耦合性,我們就可以在不同的應用中將各個切面組合使用,從而使得代碼可重用
性大大增強。
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
2. 連接點(JoinPoint)
程序運行過程中的某個階段點。如某個方法調用,或者某個異常被拋出。
3. 處理邏輯(Advice)
在某個連接點所采用的處理邏輯
(這里的Advice,國內不少文案中翻譯為“通知”,估計是源于金山詞霸,與實際含義不符,因而這
里采用意譯)
處理邏輯的調用模式通常有三種:
i. Around
在連接點前后插入預處理過程和后處理過程。
ii. Before
僅在連接點之前插入預處理過程。
iii. Throw
在連接點拋出異常時進行異常處理。
4. 切點(PointCut)
一系列連接點的集合,它指明處理方式(Advice)將在何時被觸發。
上述幾個概念我們將在稍后的“AOP應用”一節中結合實際使用進行具體探討。
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
AOP in Spring
Spring中提供的內置AOP支持,是基于動態AOP機制實現。從技術角度來講,所謂動
態AOP,即通過動態Proxy模式,在目標對象的方法調用前后插入相應的處理代碼。
而Spring AOP中的動態Proxy模式,則是基于Java Dynamic Proxy(面向Interface)
和CGLib(面向Class)實現。
前面曾經提及,Spring Framework中的“事務管理”服務,實際上是借助AOP機制
完成。我們這里就以“事務管理”為例,對動態AOP的實現加以探討,一方面對動態AOP
的實現原理加以探究,另一方面,也可以加深對Spring中事務管理機制的理解。
首先,我們來看基于Java Dynamic Proxy的AOP實現原理。
Dynamic Proxy 與Spring AOP
Dynamic Proxy是JDK 1.3版本中新引入的一種動態代理機制。它是Proxy模式的一
種動態實現版本。
我們先來看傳統方式下一個Proxy的實現實例。
假設我們有一個UserDAO接口及其實現類UserDAOImp:
UserDAO.java:
public interface UserDAO {
public void saveUser(User user);
}
UserDAOImp.java:
public class UserDAOImp implements UserDAO{
public void saveUser(User user) {
……
}
}
UserDAOImp.saveUser方法中實現了針對User對象的數據庫持久邏輯。
如果我們希望在UserDAOImp.saveUser方法執行前后追加一些處理過程,如啟動/
提交事務,而不影響外部代碼的調用邏輯,那么,增加一個Proxy類是個不錯的選擇:
UserDAOProxy.java
public class UserDAOProxy implements UserDAO {
private UserDAO userDAO;
public UserDAOProxy(UserDAO userDAO) {
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
this.userDAO = userDAO;
}
public void saveUser(User user) {
UserTransaction tx = null;
try {
tx = (UserTransaction) (
new InitialContext().lookup("java/tx")
);
userDAO.saveUser(user);
tx.commit();
} catch (Exception ex) {
if (null!=tx){
try {
tx.rollback();
}catch(Exception e) {
}
}
}
}
}
UserDAOProxy同樣是UserDAO接口的實現,對于調用者而言,saveUser方法的使
用完全相同,不同的是內部實現機制已經發生了一些變化――我們在UserDAOProxy中為
UserDAO.saveUser方法套上了一個JTA事務管理的外殼。
上面是靜態Proxy模式的一個典型實現。
現在假設系統中有20個類似的接口,針對每個接口實現一個Proxy,實在是個繁瑣無
味的苦力工程。
Dynamic Proxy的出現,為這個問題提供了一個更加聰明的解決方案。
我們來看看怎樣通過Dynamic Proxy解決上面的問題:
public class TxHandler implements InvocationHandler {
private Object originalObject;
public Object bind(Object obj) {
this.originalObject = obj;
return Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
this);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
if (!method.getName().startsWith("save")) {
UserTransaction tx = null;
try {
tx = (UserTransaction) (
new InitialContext().lookup("java/tx")
);
result = method.invoke(originalObject, args);
tx.commit();
} catch (Exception ex) {
if (null != tx) {
try {
tx.rollback();
} catch (Exception e) {
}
}
}
} else {
result = method.invoke(originalObject, args);
}
return result;
}
}
首先注意到,上面這段代碼中,并沒有出現與具體應用層相關的接口或者類引用。也就
是說,這個代理類適用于所有接口的實現。
其中的關鍵在兩個部分:
1.
return Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
this);
java.lang.reflect.Proxy.newProxyInstance方法根據傳入的接口類型
(obj.getClass().getInterfaces())動態構造一個代理類實例返回,這個代理類是JVM
在內存中動態構造的動態類,它實現了傳入的接口列表中所包含的所有接口。
這里也可以看出,Dynamic Proxy要求所代理的類必須是某個接口的實現
(obj.getClass().getInterfaces()不可為空),否則無法為其構造響應的動態類。這也
就是為什么Spring對接口實現類通過Dynamic Proxy實現AOP,而對于沒有實現任何接口
的類通過CGLIB實現AOP機制的原因,關于CGLIB,請參見稍后章節的討論。
2.
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
……
result = method.invoke(originalObject, args);
……
return result;
}
InvocationHandler.invoke方法將在被代理類的方法被調用之前觸發。通過這個方
法中,我們可以在被代理類方法調用的前后進行一些處理,如代碼中所示,
InvocationHandler.invoke方法的參數中傳遞了當前被調用的方法(Method),以及被
調用方法的參數。
同時,我們可以通過Method.invoke方法調用被代理類的原始方法實現。這樣,我們
就可以在被代理類的方法調用前后大做文章。
在示例代碼中,我們為所有名稱以“save”開頭的方法追加了JTA事務管理。
談到這里,可以回憶一下Spring事務配置中的內容:
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
想必大家已經猜測到Spring事務管理機制的實現原理。
是的,只需通過一個Dynamic Proxy對所有需要事務管理的Bean進行加載,并根據配
置,在invoke方法中對當前調用的方法名進行判定,并為其加上合適的事務管理代碼,那
么就實現了Spring式的事務管理。
當然,Spring中的AOP實現更為復雜和靈活,不過基本原理一致。
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
代碼勝千言,下面是筆者在客戶培訓過程中編寫的一個Dynamic Proxy based AOP
實現示例,非常簡單,有興趣的讀者可以看看。
AOPHandler.java:
public class AOPHandler implements InvocationHandler {
private static Log logger = LogFactory.getLog(AOPHandler.class);
private List interceptors = null;
private Object originalObject;
/**
* 返回動態代理實例
* @param obj
* @return
*/
public Object bind(Object obj) {
this.originalObject = obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj
.getClass().getInterfaces(), this);
}
/**
* 在Invoke方法中,加載對應的Interceptor,并進行
* 預處理(before)、后處理(after)以及異常處理(exceptionThrow)過程
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
Throwable ex = null;
InvocationInfo invInfo = new InvocationInfo(proxy, method, args,
result, ex);
logger.debug("Invoking Before Intercetpors!");
invokeInterceptorsBefore(invInfo);
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
try {
logger.debug("Invoking Proxy Method!");
result = method.invoke(originalObject, args);
invInfo.setResult(result);
logger.debug("Invoking After Method!");
invokeInterceptorsAfter(invInfo);
} catch (Throwable tr) {
invInfo.setException(tr);
logger.debug("Invoking exceptionThrow Method!");
invokeInterceptorsExceptionThrow(invInfo);
throw new AOPRuntimeException(tr);
}
return result;
}
/**
* 加載Interceptor
* @return
*/
private synchronized List getIntercetors() {
if (null == interceptors) {
interceptors = new ArrayList();
//Todo:讀取配置,加載Interceptor實例
//interceptors.add(new MyInterceptor());
}
return interceptors;
}
/**
* 執行預處理方法
* @param invInfo
*/
private void invokeInterceptorsBefore(InvocationInfo invInfo) {
List interceptors = getIntercetors();
int len = interceptors.size();
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
for (int i = 0; i < len; i++) {
((Interceptor) interceptors.get(i)).before(invInfo);
}
}
/**
* 執行后處理方法
* @param invInfo
*/
private void invokeInterceptorsAfter(InvocationInfo invInfo) {
List interceptors = getIntercetors();
int len = interceptors.size();
for (int i = len - 1; i >= 0; i--) {
((Interceptor) interceptors.get(i)).after(invInfo);
}
}
/**
* 執行異常處理方法
* @param invInfo
*/
private void invokeInterceptorsExceptionThrow(InvocationInfo
invInfo) {
List interceptors = getIntercetors();
int len = interceptors.size();
for (int i = len - 1; i >= 0; i--) {
((Interceptor)
interceptors.get(i)).exceptionThrow(invInfo);
}
}
}
Interceptor.java:
public interface Interceptor {
public void before(InvocationInfo invInfo);
public void after(InvocationInfo invInfo);
public void exceptionThrow(InvocationInfo invInfo);
}
InvocationInfo.java:
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
public class InvocationInfo {
Object proxy;
Method method;
Object[] args;
Object result;
Throwable Exception;
public InvocationInfo(Object proxy, Method method, Object[] args,
Object result, Throwable exception) {
super();
this.proxy = proxy;
this.method = method;
this.args = args;
this.result = result;
Exception = exception;
}
public Object getResult() {
return result;
}
public void setResult(Object result) {
this.result = result;
}
public Object[] getArgs() {
return args;
}
public void setArgs(Object[] args) {
this.args = args;
}
public Throwable getException() {
return Exception;
}
public void setException(Throwable exception) {
Exception = exception;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
public Object getProxy() {
return proxy;
}
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
public void setProxy(Object proxy) {
this.proxy = proxy;
}
}
AOPFactory.java:
public class AOPFactory {
private static Log logger = LogFactory.getLog(AOPFactory.class);
/**
* 根據類名創建類實例
* @param clzName
* @return
* @throws ClassNotFoundException
*/
public static Object getClassInstance(String clzName){
Class cls;
try {
cls = Class.forName(clzName);
return (Object)cls.newInstance();
} catch (ClassNotFoundException e) {
logger.debug(e);
throw new AOPRuntimeException(e);
} catch (InstantiationException e) {
logger.debug(e);
throw new AOPRuntimeException(e);
} catch (IllegalAccessException e) {
logger.debug(e);
throw new AOPRuntimeException(e);
}
}
/**
* 根據傳入的類名,返回AOP代理對象
* @param clzName
* @return
*/
public static Object getAOPProxyedObject(String clzName){
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
AOPHandler txHandler = new AOPHandler();
Object obj = getClassInstance(clzName);
return txHandler.bind(obj);
}
}
MyInterceptor.java:
public class MyInterceptor implements Interceptor{
private static Log logger = LogFactory.getLog(MyInterceptor.class);
public void before(InvocationInfo invInfo) {
logger.debug("Pre-processing");
}
public void after(InvocationInfo invInfo) {
logger.debug("Post-processing");
}
public void exceptionThrow(InvocationInfo invInfo) {
logger.debug("Exception-processing");
}
}
Spring中Dynamic Proxy AOP實現類為:
org.springframework.aop.framework.JdkDynamicAopProxy
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
CGLib 與Spring AOP
上面曾經提過,Dynamic Proxy是面向接口的動態代理實現,其代理對象必須是某個
接口的實現。Dynamic Proxy通過在運行期構建一個此接口的動態實現類完成對目標對象
的代理(相當于在運行期動態構造一個UserDAOProxy,完成對UserDAOImp的代理任
務)。
而如果目標代理對象并未實現任何接口,那么Dynamic Proxy就失去了創建動態代理
類的基礎依據。此時我們需要借助一些其他的機制實現動態代理機制。
Spring中,引入了CGLib作為無接口情況下的動態代理實現。
CGLib與Dynamic Proxy的代理機制基本類似,只是其動態生成的代理對象并非某個
接口的實現,而是針對目標類擴展的子類。
換句話說,Dynamic Proxy返回的動態代理類,是目標類所實現的接口的另一個實現
版本,它實現了對目標類的代理(如同UserDAOProxy與UserDAOImp的關系)。而CGLib
返回的動態代理類,則是目標代理類的一個子類(代理類擴展了UserDAOImp類)。
與Dynamic Proxy中的Proxy和InvocationHandler相對應,Enhancer和
MethodInterceptor在CGLib中負責完成代理對象創建和方法截獲處理。
下面是通過CGLib進行動態代理的示例代碼:
AOPInstrumenter.java:
public class AOPInstrumenter implements MethodInterceptor {
private static Log logger =
LogFactory.getLog(AOPInstrumenter.class);
private Enhancer enhancer = new Enhancer();
public Object getInstrumentedClass(Class clz) {
enhancer.setSuperclass(clz);
enhancer.setCallback(this);
return enhancer.create();
}
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
public Object intercept(
Object o,
Method method,
Object[] methodParameters,
MethodProxy methodProxy)
throws Throwable {
logger.debug("Before Method =>"+method.getName());
Object result = methodProxy.invokeSuper(o, methodParameters);
logger.debug("After Method =>"+method.getName());
return result;
}
}
測試代碼:
AOPInstrumenter aopInst = new AOPInstrumenter();
UserDAOImp userDAO =
(UserDAOImp) aopInst.getInstrumentedClass(UserDAOImp.class);
User user = new User();
user.setName("Erica");
userDAO.saveUser(user);
有興趣的讀者可以利用CGLib對Dynamic Proxy中給出的AOP實現代碼進行改造。
Spring中,基于CGLib的AOP實現位于:
org.springframework.aop.framework.Cglib2AopProxy
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
AOP 應用
前面介紹AOP概念的章節中,曾經以權限檢查為例說明AOP切面的概念。
權限檢查的確是AOP應用中一個熱門話題,假設如果現在出現了一個設計完備的權限
管理組件,那么將是一件多么愜意的事情,我們只需要在系統中配置一個AOP組件,即可
完成以往需要大費周張才能完成的權限判定功能。
可惜目前還沒有這樣一個很完善的實現。一方面權限檢查過于復雜多變,不同的業務系
統中的權限判定邏輯可能多種多樣(如對于某些關鍵系統而言,很可能出現需要同時輸入兩
個人的密碼才能訪問的需求)。另一方面,就目前的AOP應用粒度而言,“權限管理”作為
一個切面尚顯得過于龐大,需要進一步切分設計,設計復雜,實現難度較大。
目前最為實用的AOP應用,可能就是Spring中基于AOP實現的事務管理機制,也正是
這一點,使得Spring AOP大放異彩。
之前的內容中,我們大多圍繞Spring AOP的實現原理進行探討,這里我們圍繞一個簡
單的AOP Interceptor實例,看看Spring中AOP機制的應用與開發。
在應用系統開發過程中,我們通常需要對系統的運行性能有所把握,特別是對于關鍵業
務邏輯的執行效能,而對于執行效能中的執行時間,則可能是重中之重。
我們這里的實例的實現目標,就是打印出目標Bean中方法的執行時間。
首先,圍繞開篇中提到的幾個重要概念,我們來看看Spring中對應的實現。
1. 切點(PointCut)
一系列連接點的集合,它指明處理方式(Advice)將在何時被觸發。
對于我們引用開發而言,“何時觸發”的條件大多是面向Bean的方法進行制定。實
際上,只要我們在開發中用到了Spring的配置化事務管理,那么就已經進行了PointCut
設置,我們可以指定對所有save開頭的方法進行基于AOP的事務管理:
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
</props>
</property>
同樣,對于我們的AOP組件而言,我們也可以以方法名作為觸發判定條件。
我們可以通過以下節點,為我們的組件設定觸發條件。
<bean id="myPointcutAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdv
isor">
<property name="advice">
<ref local="MyInterceptor" />
</property>
<property name="patterns">
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
<list>
<value>.*do.*</value>
<value>.*execute.*</value>
</list>
</property>
</bean>
RegexpMethodPointcutAdvisor是Spring中提供的,通過邏輯表達式指定方法
判定條件的支持類。其中的邏輯表達式解析采用了Apache ORO組件實現,關于邏
輯表達式的語法請參見Apache ORO文檔。
上面我們針對MyInterceptor設定了一個基于方法名的觸發條件,也就是說,當
目標類的指定方法運行時,MyInterceptor即被觸發。
MyInterceptor是我們對應的AOP邏輯處理單元,也就是所謂的Advice。
2. Advice
Spring中提供了以下幾種Advice:
1. Interception around advice
Spring中最基本的Advice類型,提供了針對PointCut的預處理、后處理過程
支持。
我們將使用Interception around advice完成這里的實例。
2. Before advice
僅面向了PointCut的預處理。
3. Throws advice
僅面向PointCut的后處理過程中的異常處理。
4. After Returning advice
僅面向PointCut返回后的后處理過程。
5. Introduction advice
Spring中較為特殊的一種Advice,僅面向Class層面(而不像上述Advice面
向方法層面)。通過Introduction advice我們可以實現多線程訪問中的類鎖
定。
Spring中采用了AOP聯盟(AOP Alliance)12的通用AOP接口(接口定義位于
aopalliance.jar)。這里我們采用aopalliance.jar中定義的MethodInterceptor作為
我們的Advice實現接口:
public class MethodTimeCostInterceptor implements
MethodInterceptor,
Serializable {
protected static final Log logger = LogFactory
12 http://aopalliance.sourceforge.net/
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
.getLog(MethodTimeCostInterceptor.class);
public Object invoke(MethodInvocation invocation) throws
Throwable {
long time = System.currentTimeMillis();
Object rval = invocation.proceed();
time = System.currentTimeMillis() - time;
logger.info("Method Cost Time => " + time + " ms");
return rval;
}
}
對應配置如下:
<bean id="MyInterceptor"
class="net.xiaxin.interceptors.MethodTimeCostInterceptor"
/>
除此之外,我們還需要定義一個Spring AOP ProxyFactory用以加載執行AOP組件。
定義如下:
<bean id="myAOPProxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>net.xiaxin.ITest</value>
</property>
<!—是否強制使用CGLIB進行動態代理
<property name="proxyTargetClass">
<value>true</value>
</property>
-->
<property name="target">
<ref local="test" />
</property>
<property name="interceptorNames">
<value>myPointcutAdvisor</value>
</property>
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
</bean>
<bean id="test" class="net.xiaxin.Test"/>
其中的test是我們用于測試的一個類,它實現了ITest接口。
public interface ITest {
public abstract void doTest();
public abstract void executeTest();
}
public class Test implements ITest {
public void doTest(){
for (int i=0;i<10000;i++){}
}
public void executeTest(){
for (int i=0;i<25000;i++){}
}
}
通過以上工作,我們的MyInterceptor即被加載,并將在Test.doTest和
Test.executeTest方法調用時被觸發,打印出這兩個方法的執行時間。
public void testAOP() {
ApplicationContext ctx=new
FileSystemXmlApplicationContext("bean.xml");
ITest test = (ITest) ctx.getBean("myAOPProxy");
test.doTest();
test.executeTest();
}
引自:http://hi.baidu.com/zbzb/blog/item/0d6fa7ec0823c63f279791d8.html