NO IMAGE

 

原先以為自己已經瞭解了AOP,昨天又看了看,發現還是有些地方沒有弄明白,再記錄一篇文章以便理解
轉自:http://spring.jactiongroup.net/viewtopic.php?t=478
這是在網上發現的一篇關於Spring AOP程式設計的教程,讀完這篇文章後,Spring AOP不再難以理解,因此我把它譯成中文,推薦給Spring AOP的初學者。這是譯文的連結

AOP正在成為軟體開發的下一個聖盃。使用AOP,你可以將處理aspect的程式碼注入主程式,通常主程式的主要目的並不在於處理這些aspect。AOP可以防止程式碼混亂。
為了理解AOP如何做到這點,考慮一下記日誌的工作。日誌本身不太可能是你開發的主程式的主要任務。如果能將“不可見的”、通用的日誌程式碼注入主程式中,那該多好啊。AOP可以幫助你做到。
Spring framework是很有前途的AOP技術。作為一種非侵略性的,輕型的AOP framework,你無需使用預編譯器或其他的元標籤,便可以在Java程式中使用它。這意味著開發團隊裡只需一人要對付AOP framework,其他人還是象往常一樣程式設計。
AOP是很多直覺難以理解的術語的根源。幸運的是,你只要理解三個概念,就可以編寫AOP模組。這三個概念是:advice,pointcut和advisor。advice是你想向別的程式內部不同的地方注入的程式碼。pointcut定義了需要注入advice的位置,通常是某個特定的類的一個public方法。advisor是pointcut和advice的裝配器,是將advice注入主程式中預定義位置的程式碼。

既然我們知道了需要使用advisor向主要程式碼中注入“不可見的”advice,讓我們實現一個Spring AOP的例子。在這個例子中,我們將實現一個before advice,這意味著advice的程式碼在被呼叫的public方法開始前被執行。以下是這個before advice的實現程式碼:

程式碼:
package com.company.springaop.test;

import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;

public class TestBeforeAdvice implements MethodBeforeAdvice {

  public void before(Method m, Object[] args, Object target)
  throws Throwable {
    System.out.println(“Hello world! (by ”
        this.getClass().getName()
        “)”);
  }
}
 

介面MethodBeforeAdvice只有一個方法before需要實現,它定義了advice的實現。before方法共用三個引數,它們提供了相當豐富的資訊。引數Method m是advice開始後執行的方法。方法名稱可以用作判斷是否執行程式碼的條件。Object[] args是傳給被呼叫的public方法的引數陣列。當需要記日誌時,引數args和被執行方法的名稱,都是非常有用的資訊。你也可以改變傳給m的引數,但要小心使用這個功能;編寫最初主程式的程式設計師並不知道主程式可能會和傳入引數的發生衝突。Object target是執行方法m物件的引用。

在下面的BeanImpl類中,每個public方法呼叫前,都會執行advice:

程式碼:
package com.company.springaop.test;

public class BeanImpl implements Bean {

  public void theMethod() {
    System.out.println(this.getClass().getName()
        “.” new Exception().getStackTrace()[0].getMethodName()
        “()”
        ” says HELLO!”);
  }
}

類BeanImpl實現了下面的介面Bean:

程式碼:
package com.company.springaop.test;

public interface Bean {
  public void theMethod();
}

雖然不是必須使用介面,但面向介面而不是面向實現程式設計是良好的程式設計實踐,Spring也鼓勵這樣做。

pointcut和advice通過配置檔案來實現,因此,接下來你只需編寫主方法的Java程式碼:

程式碼:

package com.company.springaop.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class Main {

  public static void main(String[] args) {
    //Read the configuration file
    ApplicationContext ctx
        = new FileSystemXmlApplicationContext(“springconfig.xml”);

    //Instantiate an object
    Bean x = (Bean) ctx.getBean(“bean”);

    //Execute the public method of the bean (the test)
    x.theMethod();
  }
}

我們從讀入和處理配置檔案開始,接下來馬上要建立它。這個配置檔案將作為粘合程式不同部分的“膠水”。讀入和處理配置檔案後,我們會得到一個建立工廠ctx。任何一個Spring管理的物件都必須通過這個工廠來建立。物件通過工廠建立後便可正常使用。

僅僅用配置檔案便可把程式的每一部分組裝起來。

程式碼:
<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE beans PUBLIC  “-//SPRING//DTD BEAN//EN” “http://www.springframework.org/dtd/spring-beans.dtd”>

<beans>
  <!–CONFIG–>
  <bean id=”bean” class=”org.springframework.aop.framework.ProxyFactoryBean”>
    <property name=”proxyInterfaces”>
      <value>com.company.springaop.test.Bean</value>
    </property>
    <property name=”target”>
      <ref local=”beanTarget”/>
    </property>
    <property name=”interceptorNames”>
      <list>
        <value>theAdvisor</value>
      </list>
    </property>
  </bean>

  <!–CLASS–>
  <bean id=”beanTarget” class=”com.company.springaop.test.BeanImpl”/>

  <!–ADVISOR–>
  <!–Note: An advisor assembles pointcut and advice–>
  <bean id=”theAdvisor” class=”org.springframework.aop.support.RegexpMethodPointcutAdvisor”>
    <property name=”advice”>
      <ref local=”theBeforeAdvice”/>
    </property>
    <property name=”pattern”>
      <value>com/.company/.springaop/.test/.Bean/.theMethod</value>
    </property>
  </bean>

  <!–ADVICE–>
  <bean id=”theBeforeAdvice” class=”com.company.springaop.test.TestBeforeAdvice”/>
</beans>
 

四個bean定義的次序並不重要。我們現在有了一個advice,一個包含了正規表示式pointcut的advisor,一個主程式類和一個配置好的介面,通過工廠ctx,這個介面返回自己本身實現的一個引用。

BeanImpl和TestBeforeAdvice都是直接配置。我們用一個唯一的ID建立一個bean元素,並指定了一個實現類。這就是全部的工作。

advisor通過Spring framework提供的一個RegexMethodPointcutAdvisor類來實現。我們用advisor的一個屬性來指定它所需的advice-bean。第二個屬性則用正規表示式定義了pointcut,確保良好的效能和易讀性。

最後配置的是bean,它可以通過一個工廠來建立。bean的定義看起來比實際上要複雜。bean是ProxyFactoryBean的一個實現,它是Spring framework的一部分。這個bean的行為通過一下的三個屬性來定義:

  • 屬性proxyInterface定義了介面類。
  • 屬性target指向本地配置的一個bean,這個bean返回一個介面的實現。
  • 屬性interceptorNames是唯一允許定義一個值列表的屬性。這個列表包含所有需要在beanTarget上執行的advisor。注意,advisor列表的次序是非常重要的。

Spring工具

雖然你可以手工修改Ant構建指令碼,但使用SpringUI(譯註:SpringUI現在是Spring framework的一部分,並改名為spring-ide),使用Spring AOP變得很簡單,只要點點滑鼠即可。你可以把SpringUI安裝成Eclipse的一個plug-in。然後,你只需在你的project上右擊滑鼠,並選擇“add Spring Project Nature”。在project屬性中,你可以在“Spring Project”下新增Spring配置檔案。在編譯前把下面的類庫加入project:aopalliance.jar,commons-logging.jar,jakarta-oro-2.0.7.jar和spring.jar。執行程式時你會看到下面的資訊:

… (logging information)
Hello world! (by com.company.springaop.test.TestBeforeAdvice)
com.company.springaop.test.BeanImpl.theMethod() says HELLO!

優點和缺點

Spring比起其他的framework更有優勢,因為除了AOP以外,它提供了更多別的功能。作為一個輕型framework,它在J2EE不同的部分都可以發揮作用。因此,即使不想使用Spring AOP,你可能還是想使用Spring。另一個優點是,Spring並不要求開發團隊所有的人員都會用它。學習Spring應該從Spring reference的第一頁開始。讀了本文後,你應該可以更好地理解Spring reference了。Spring唯一的缺點是缺乏更多的文件,但它的mailing list是個很好的補充,而且會不斷地出現更多的文件。