<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    我的Blog我做主^_^

    走向一條通往JAVA的不歸路...

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      64 隨筆 :: 68 文章 :: 77 評論 :: 0 Trackbacks

    Aspect Oriented Programming
    AOP概念
    Aspect Oriented Programming(AOP)是近來較為熱門的一個話題。AOP,國內(nèi)
    大致譯作“面向方面編程”。
    “面向方面編程”,這樣的名字并不是非常容易理解,且容易產(chǎn)生一些誤導(dǎo)。筆者不止
    一次聽到類似“OOP/OOD11即將落伍,AOP是新一代軟件開發(fā)方式”這樣的發(fā)言。顯然,
    發(fā)言者并沒有理解AOP的含義。
    Aspect,沒錯,的確是“方面”的意思。不過,華語傳統(tǒng)語義中的“方面”,大多數(shù)情
    況下指的是一件事情的不同維度、或者說不同角度上的特性,比如我們常說:“這件事情要
    從幾個方面來看待”,往往意思是:需要從不同的角度來看待同一個事物。這里的“方面”,
    指的是事務(wù)的外在特性在不同觀察角度下的體現(xiàn)。
    而在AOP中,Aspect的含義,可能更多的理解為“切面”比較合適。所以筆者更傾向
    于“面向切面編程”的譯法。
    另外需要提及的是,AOP、OOP在字面上雖然非常類似,但卻是面向不同領(lǐng)域的兩種
    設(shè)計思想。OOP(面向?qū)ο缶幊蹋┽槍I(yè)務(wù)處理過程的實體及其屬性和行為進行抽象封裝,
    以獲得更加清晰高效的邏輯單元劃分。
    而AOP則是針對業(yè)務(wù)處理過程中的切面進行提取,它所面對的是處理過程中的某個步
    驟或階段,以獲得邏輯過程中各部分之間低耦合性的隔離效果。這兩種設(shè)計思想在目標上有
    著本質(zhì)的差異。
    上面的陳述可能過于理論化,舉個簡單的例子,對于“雇員”這樣一個業(yè)務(wù)實體進行封
    裝,自然是OOP/OOD的任務(wù),我們可以為其建立一個“Employee”類,并將“雇員”相
    關(guān)的屬性和行為封裝其中。而用AOP設(shè)計思想對“雇員”進行封裝將無從談起。
    同樣,對于“權(quán)限檢查”這一動作片斷進行劃分,則是AOP的目標領(lǐng)域。而通過OOD/OOP
    對一個動作進行封裝,則有點不倫不類。
    換而言之,OOD/OOP面向名詞領(lǐng)域,AOP面向動詞領(lǐng)域。
    AOP和OOD/OOP并不沖突,我們完全可以在一個應(yīng)用系統(tǒng)中同時應(yīng)用OOD/OOP和
    AOP設(shè)計思想,通過OOD/OOP對系統(tǒng)中的業(yè)務(wù)對象進行建模,同時通過AOP對實體處理
    過程中的階段進行隔離處理。即使不是OOD/OOP,而是在傳統(tǒng)的POP(面向過程編程)中,
    AOP也能起到同樣的作用。
    將不同階段領(lǐng)域加以分隔,這是否就算是AOP呢?
    AOP還有另外一個重要特點:源碼組成無關(guān)性。
    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?
    倘若應(yīng)用中通過某個具體的業(yè)務(wù)邏輯類實現(xiàn)了獨立的權(quán)限檢查,而請求調(diào)度方法通過預(yù)
    編碼調(diào)用這個權(quán)限模塊實現(xiàn)權(quán)限管理。那么這也不算是AOP。對于AOP組件而言,很重要
    的一點就是源碼組成無關(guān)性,所謂源碼組成無關(guān)性,體現(xiàn)在具體設(shè)計中就是AOP組件必須
    與應(yīng)用代碼無關(guān),簡單來講,就是應(yīng)用代碼可以脫離AOP組件獨立編譯。
    為了實現(xiàn)源碼組成無關(guān)性,AOP往往通過預(yù)編譯方式(如AspectJ)和運行期動態(tài)代理
    模式(如Spring AOP 和JBoss AOP)實現(xiàn)。
    稍后章節(jié)中我們會就Spring Framework中的AOP實現(xiàn)機制進行更加深入的探討。
    下面先來看AOP中幾個比較重要的概念:
    1. 切面(Aspect)
    切面,對象操作過程中的截面。這可能是AOP中最關(guān)鍵的一個術(shù)語。
    我們首先來看一個應(yīng)用開發(fā)中常見的切面:用戶權(quán)限檢查。大概只要是完整的應(yīng)用,都
    少不了用戶權(quán)限檢查這個模塊,不同身份的用戶可以做什么,不可以做什么,均由這個模塊
    加以判定。而這個模塊調(diào)用的位置通常也比較固定:用戶發(fā)起請求之后,執(zhí)行業(yè)務(wù)邏輯之前。
    針對權(quán)限檢查這一模塊進行分離,我們就得到了一個切面:
    切面意義何在?
    首先根據(jù)上例,假設(shè)我們實現(xiàn)了一個通用的權(quán)限檢查模塊,那么就可以在這層切面上進
    行統(tǒng)一的集中式權(quán)限管理。而業(yè)務(wù)邏輯組件則無需關(guān)心權(quán)限方面的問題。也就是說,通過切
    面,我們可以將系統(tǒng)中各個不同層次上的問題隔離開來,實現(xiàn)統(tǒng)一集約式處理。各切面只需
    集中于自己領(lǐng)域內(nèi)的邏輯實現(xiàn)。
    這一方面使得開發(fā)邏輯更加清晰,專業(yè)化分工更加易于進行;另一方面,由于切面的隔
    離,降低了耦合性,我們就可以在不同的應(yīng)用中將各個切面組合使用,從而使得代碼可重用
    性大大增強。
    SpringFrameWork Developer’s Guide Version 0.6
    October 8, 2004 So many open source projects. Why not Open your Documents?
    2. 連接點(JoinPoint)
    程序運行過程中的某個階段點。如某個方法調(diào)用,或者某個異常被拋出。
    3. 處理邏輯(Advice)
    在某個連接點所采用的處理邏輯
    (這里的Advice,國內(nèi)不少文案中翻譯為“通知”,估計是源于金山詞霸,與實際含義不符,因而這
    里采用意譯)
    處理邏輯的調(diào)用模式通常有三種:
    i. Around
    在連接點前后插入預(yù)處理過程和后處理過程。
    ii. Before
    僅在連接點之前插入預(yù)處理過程。
    iii. Throw
    在連接點拋出異常時進行異常處理。
    4. 切點(PointCut)
    一系列連接點的集合,它指明處理方式(Advice)將在何時被觸發(fā)。
    上述幾個概念我們將在稍后的“AOP應(yīng)用”一節(jié)中結(jié)合實際使用進行具體探討。
    SpringFrameWork Developer’s Guide Version 0.6
    October 8, 2004 So many open source projects. Why not Open your Documents?
    AOP in Spring
    Spring中提供的內(nèi)置AOP支持,是基于動態(tài)AOP機制實現(xiàn)。從技術(shù)角度來講,所謂動
    態(tài)AOP,即通過動態(tài)Proxy模式,在目標對象的方法調(diào)用前后插入相應(yīng)的處理代碼。
    而Spring AOP中的動態(tài)Proxy模式,則是基于Java Dynamic Proxy(面向Interface)
    和CGLib(面向Class)實現(xiàn)。
    前面曾經(jīng)提及,Spring Framework中的“事務(wù)管理”服務(wù),實際上是借助AOP機制
    完成。我們這里就以“事務(wù)管理”為例,對動態(tài)AOP的實現(xiàn)加以探討,一方面對動態(tài)AOP
    的實現(xiàn)原理加以探究,另一方面,也可以加深對Spring中事務(wù)管理機制的理解。
    首先,我們來看基于Java Dynamic Proxy的AOP實現(xiàn)原理。
    Dynamic Proxy 與Spring AOP
    Dynamic Proxy是JDK 1.3版本中新引入的一種動態(tài)代理機制。它是Proxy模式的一
    種動態(tài)實現(xiàn)版本。
    我們先來看傳統(tǒng)方式下一個Proxy的實現(xiàn)實例。
    假設(shè)我們有一個UserDAO接口及其實現(xiàn)類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方法中實現(xiàn)了針對User對象的數(shù)據(jù)庫持久邏輯。
    如果我們希望在UserDAOImp.saveUser方法執(zhí)行前后追加一些處理過程,如啟動/
    提交事務(wù),而不影響外部代碼的調(diào)用邏輯,那么,增加一個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接口的實現(xiàn),對于調(diào)用者而言,saveUser方法的使
    用完全相同,不同的是內(nèi)部實現(xiàn)機制已經(jīng)發(fā)生了一些變化――我們在UserDAOProxy中為
    UserDAO.saveUser方法套上了一個JTA事務(wù)管理的外殼。
    上面是靜態(tài)Proxy模式的一個典型實現(xiàn)。
    現(xiàn)在假設(shè)系統(tǒng)中有20個類似的接口,針對每個接口實現(xiàn)一個Proxy,實在是個繁瑣無
    味的苦力工程。
    Dynamic Proxy的出現(xiàn),為這個問題提供了一個更加聰明的解決方案。
    我們來看看怎樣通過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;
    }
    }
    首先注意到,上面這段代碼中,并沒有出現(xiàn)與具體應(yīng)用層相關(guān)的接口或者類引用。也就
    是說,這個代理類適用于所有接口的實現(xiàn)。
    其中的關(guān)鍵在兩個部分:
    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方法根據(jù)傳入的接口類型
    (obj.getClass().getInterfaces())動態(tài)構(gòu)造一個代理類實例返回,這個代理類是JVM
    在內(nèi)存中動態(tài)構(gòu)造的動態(tài)類,它實現(xiàn)了傳入的接口列表中所包含的所有接口。
    這里也可以看出,Dynamic Proxy要求所代理的類必須是某個接口的實現(xiàn)
    (obj.getClass().getInterfaces()不可為空),否則無法為其構(gòu)造響應(yīng)的動態(tài)類。這也
    就是為什么Spring對接口實現(xiàn)類通過Dynamic Proxy實現(xiàn)AOP,而對于沒有實現(xiàn)任何接口
    的類通過CGLIB實現(xiàn)AOP機制的原因,關(guān)于CGLIB,請參見稍后章節(jié)的討論。
    2.
    public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable {
    ……
    result = method.invoke(originalObject, args);
    ……
    return result;
    }
    InvocationHandler.invoke方法將在被代理類的方法被調(diào)用之前觸發(fā)。通過這個方
    法中,我們可以在被代理類方法調(diào)用的前后進行一些處理,如代碼中所示,
    InvocationHandler.invoke方法的參數(shù)中傳遞了當前被調(diào)用的方法(Method),以及被
    調(diào)用方法的參數(shù)。
    同時,我們可以通過Method.invoke方法調(diào)用被代理類的原始方法實現(xiàn)。這樣,我們
    就可以在被代理類的方法調(diào)用前后大做文章。
    在示例代碼中,我們?yōu)樗忻Q以“save”開頭的方法追加了JTA事務(wù)管理。
    談到這里,可以回憶一下Spring事務(wù)配置中的內(nèi)容:
    <property name="transactionAttributes">
    <props>
    <prop key="save*">PROPAGATION_REQUIRED</prop>
    <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
    </props>
    </property>
    想必大家已經(jīng)猜測到Spring事務(wù)管理機制的實現(xiàn)原理。
    是的,只需通過一個Dynamic Proxy對所有需要事務(wù)管理的Bean進行加載,并根據(jù)配
    置,在invoke方法中對當前調(diào)用的方法名進行判定,并為其加上合適的事務(wù)管理代碼,那
    么就實現(xiàn)了Spring式的事務(wù)管理。
    當然,Spring中的AOP實現(xiàn)更為復(fù)雜和靈活,不過基本原理一致。
    SpringFrameWork Developer’s Guide Version 0.6
    October 8, 2004 So many open source projects. Why not Open your Documents?
    代碼勝千言,下面是筆者在客戶培訓(xùn)過程中編寫的一個Dynamic Proxy based AOP
    實現(xiàn)示例,非常簡單,有興趣的讀者可以看看。
    AOPHandler.java:
    public class AOPHandler implements InvocationHandler {
    private static Log logger = LogFactory.getLog(AOPHandler.class);
    private List interceptors = null;
    private Object originalObject;
    /**
    * 返回動態(tài)代理實例
    * @param obj
    * @return
    */
    public Object bind(Object obj) {
    this.originalObject = obj;
    return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
    obj
    .getClass().getInterfaces(), this);
    }
    /**
    * 在Invoke方法中,加載對應(yīng)的Interceptor,并進行
    * 預(yù)處理(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;
    }
    /**
    * 執(zhí)行預(yù)處理方法
    * @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);
    }
    }
    /**
    * 執(zhí)行后處理方法
    * @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);
    }
    }
    /**
    * 執(zhí)行異常處理方法
    * @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);
    /**
    * 根據(jù)類名創(chuàng)建類實例
    * @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);
    }
    }
    /**
    * 根據(jù)傳入的類名,返回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實現(xiàn)類為:
    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
    上面曾經(jīng)提過,Dynamic Proxy是面向接口的動態(tài)代理實現(xiàn),其代理對象必須是某個
    接口的實現(xiàn)。Dynamic Proxy通過在運行期構(gòu)建一個此接口的動態(tài)實現(xiàn)類完成對目標對象
    的代理(相當于在運行期動態(tài)構(gòu)造一個UserDAOProxy,完成對UserDAOImp的代理任
    務(wù))。
    而如果目標代理對象并未實現(xiàn)任何接口,那么Dynamic Proxy就失去了創(chuàng)建動態(tài)代理
    類的基礎(chǔ)依據(jù)。此時我們需要借助一些其他的機制實現(xiàn)動態(tài)代理機制。
    Spring中,引入了CGLib作為無接口情況下的動態(tài)代理實現(xiàn)。
    CGLib與Dynamic Proxy的代理機制基本類似,只是其動態(tài)生成的代理對象并非某個
    接口的實現(xiàn),而是針對目標類擴展的子類。
    換句話說,Dynamic Proxy返回的動態(tài)代理類,是目標類所實現(xiàn)的接口的另一個實現(xiàn)
    版本,它實現(xiàn)了對目標類的代理(如同UserDAOProxy與UserDAOImp的關(guān)系)。而CGLib
    返回的動態(tài)代理類,則是目標代理類的一個子類(代理類擴展了UserDAOImp類)。
    與Dynamic Proxy中的Proxy和InvocationHandler相對應(yīng),Enhancer和
    MethodInterceptor在CGLib中負責(zé)完成代理對象創(chuàng)建和方法截獲處理。
    下面是通過CGLib進行動態(tài)代理的示例代碼:
    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實現(xiàn)代碼進行改造。
    Spring中,基于CGLib的AOP實現(xiàn)位于:
    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 應(yīng)用
    前面介紹AOP概念的章節(jié)中,曾經(jīng)以權(quán)限檢查為例說明AOP切面的概念。
    權(quán)限檢查的確是AOP應(yīng)用中一個熱門話題,假設(shè)如果現(xiàn)在出現(xiàn)了一個設(shè)計完備的權(quán)限
    管理組件,那么將是一件多么愜意的事情,我們只需要在系統(tǒng)中配置一個AOP組件,即可
    完成以往需要大費周張才能完成的權(quán)限判定功能。
    可惜目前還沒有這樣一個很完善的實現(xiàn)。一方面權(quán)限檢查過于復(fù)雜多變,不同的業(yè)務(wù)系
    統(tǒng)中的權(quán)限判定邏輯可能多種多樣(如對于某些關(guān)鍵系統(tǒng)而言,很可能出現(xiàn)需要同時輸入兩
    個人的密碼才能訪問的需求)。另一方面,就目前的AOP應(yīng)用粒度而言,“權(quán)限管理”作為
    一個切面尚顯得過于龐大,需要進一步切分設(shè)計,設(shè)計復(fù)雜,實現(xiàn)難度較大。
    目前最為實用的AOP應(yīng)用,可能就是Spring中基于AOP實現(xiàn)的事務(wù)管理機制,也正是
    這一點,使得Spring AOP大放異彩。
    之前的內(nèi)容中,我們大多圍繞Spring AOP的實現(xiàn)原理進行探討,這里我們圍繞一個簡
    單的AOP Interceptor實例,看看Spring中AOP機制的應(yīng)用與開發(fā)。
    在應(yīng)用系統(tǒng)開發(fā)過程中,我們通常需要對系統(tǒng)的運行性能有所把握,特別是對于關(guān)鍵業(yè)
    務(wù)邏輯的執(zhí)行效能,而對于執(zhí)行效能中的執(zhí)行時間,則可能是重中之重。
    我們這里的實例的實現(xiàn)目標,就是打印出目標Bean中方法的執(zhí)行時間。
    首先,圍繞開篇中提到的幾個重要概念,我們來看看Spring中對應(yīng)的實現(xiàn)。
    1. 切點(PointCut)
    一系列連接點的集合,它指明處理方式(Advice)將在何時被觸發(fā)。
    對于我們引用開發(fā)而言,“何時觸發(fā)”的條件大多是面向Bean的方法進行制定。實
    際上,只要我們在開發(fā)中用到了Spring的配置化事務(wù)管理,那么就已經(jīng)進行了PointCut
    設(shè)置,我們可以指定對所有save開頭的方法進行基于AOP的事務(wù)管理:
    <property name="transactionAttributes">
    <props>
    <prop key="save*">PROPAGATION_REQUIRED</prop>
    </props>
    </property>
    同樣,對于我們的AOP組件而言,我們也可以以方法名作為觸發(fā)判定條件。
    我們可以通過以下節(jié)點,為我們的組件設(shè)定觸發(fā)條件。
    <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組件實現(xiàn),關(guān)于邏
    輯表達式的語法請參見Apache ORO文檔。
    上面我們針對MyInterceptor設(shè)定了一個基于方法名的觸發(fā)條件,也就是說,當
    目標類的指定方法運行時,MyInterceptor即被觸發(fā)。
    MyInterceptor是我們對應(yīng)的AOP邏輯處理單元,也就是所謂的Advice。
    2. Advice
    Spring中提供了以下幾種Advice:
    1. Interception around advice
    Spring中最基本的Advice類型,提供了針對PointCut的預(yù)處理、后處理過程
    支持。
    我們將使用Interception around advice完成這里的實例。
    2. Before advice
    僅面向了PointCut的預(yù)處理。
    3. Throws advice
    僅面向PointCut的后處理過程中的異常處理。
    4. After Returning advice
    僅面向PointCut返回后的后處理過程。
    5. Introduction advice
    Spring中較為特殊的一種Advice,僅面向Class層面(而不像上述Advice面
    向方法層面)。通過Introduction advice我們可以實現(xiàn)多線程訪問中的類鎖
    定。
    Spring中采用了AOP聯(lián)盟(AOP Alliance)12的通用AOP接口(接口定義位于
    aopalliance.jar)。這里我們采用aopalliance.jar中定義的MethodInterceptor作為
    我們的Advice實現(xiàn)接口:
    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;
    }
    }
    對應(yīng)配置如下:
    <bean id="MyInterceptor"
    class="net.xiaxin.interceptors.MethodTimeCostInterceptor"
    />
    除此之外,我們還需要定義一個Spring AOP ProxyFactory用以加載執(zhí)行AOP組件。
    定義如下:
    <bean id="myAOPProxy"
    class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces">
    <value>net.xiaxin.ITest</value>
    </property>
    <!—是否強制使用CGLIB進行動態(tài)代理
    <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是我們用于測試的一個類,它實現(xiàn)了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方法調(diào)用時被觸發(fā),打印出這兩個方法的執(zhí)行時間。
    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



    posted on 2007-11-13 13:47 java_蟈蟈 閱讀(570) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 午夜免费福利在线观看| 精品免费视在线观看| 免费无码又爽又刺激高潮的视频 | 国内成人精品亚洲日本语音| 波多野结衣在线免费视频| 久久久亚洲欧洲日产国码是AV| 最新国产乱人伦偷精品免费网站 | 久久亚洲日韩精品一区二区三区| 亚洲乱亚洲乱淫久久| 日本视频在线观看永久免费| 亚洲AV成人片色在线观看| 0588影视手机免费看片| 亚洲五月综合网色九月色| 中文字幕av免费专区| 亚洲电影中文字幕| 69堂人成无码免费视频果冻传媒| 亚洲入口无毒网址你懂的| 国产国产人免费人成免费视频| 亚洲人成电影在在线观看网色| 8x8x华人永久免费视频| 亚洲色婷婷六月亚洲婷婷6月| 亚洲mv国产精品mv日本mv| 精品国产免费一区二区| 国产V片在线播放免费无码| 亚洲国产精品久久久久网站| 日韩免费一区二区三区在线播放| 久久综合图区亚洲综合图区| 真人做人试看60分钟免费视频| 亚洲aⅴ无码专区在线观看| 国产亚洲精久久久久久无码77777 国产亚洲精品成人AA片新蒲金 | 亚洲国产香蕉碰碰人人| 成人免费视频软件网站| 人碰人碰人成人免费视频| 四虎影视永久免费观看地址| 成人午夜视频免费| sihu国产精品永久免费| 亚洲视频免费观看| 免费在线观看毛片| 亚洲视频免费一区| 丰满妇女做a级毛片免费观看 | 成熟女人特级毛片www免费|