Spring Framework中的面向方面編程(AOP),第一部分
時間:2005-12-16作者:Russell Miles
瀏覽次數: 5882
本文關鍵字:Java,?Spring,?aspect-oriented programming,?AOP,?crosscutting,?面向方面編程,?橫切,?延遲加載
作為這個介紹Spring框架中的面向方面編程(Aspect-Oriented Programming,AOP)的系列的第一部分,本文介紹了使您可以使用Spring中的面向方面特性進行快速開發的基礎知識。使用跟蹤和記錄方面(面向方面領域的HelloWorld)作為例子,本文展示了如何使用Spring框架所獨有的特性來聲明切入點和通知以便應用方面。本系列的第二部分將更深入地介紹如何運用Spring中的所有通知類型和切入點來實現更實用的方面和面向方面設計模式。對于AOP的更一般性的介紹,請查看ONJava站點上Graham O'Regan的文章,“Introduction to Aspect-Oriented Programming”。
本文的目的不是要介紹構成模塊化J2EE系統——即Spring框架——的所有重要元素,我們將只把注意力放在Spring所提供的AOP功能上。由于Spring的模塊化設計方法,我們可以只使用該框架的AOP元素,而無需對構成Spring框架的其他模塊做太多考慮。
在AOP方面,Spring提供了什么?
“它的目標不是提供最完善的AOP實現(雖然Spring AOP非常強大);而是要提供AOP實現與Spring IoC的緊密集成,以便幫助解決企業應用中的常見問題。”
Spring Framework參考文檔
為了實現這個目標,Spring框架目前支持一組AOP概念,從切入點到通知。本文將展示如何使用Spring框架中所實現的如下AOP概念:
- 通知(Advice):如何將before通知、afterReturning通知和afterThrowing通知聲明為bean。
- 切入點(Pointcut):如何聲明靜態切入點邏輯以將XML Spring Bean Configuration文件中的所有內容聯系在一起。
- Advisor:關聯切入點定義與通知bean的方式。
設置場景:一個簡單的例子應用程序
“一般而言,Spring并不是預描述的。雖然使用好的實踐非常容易,但是它避免強制推行一種特定的方法。”
Spring Framework參考文檔
要試用Spring框架的AOP功能,首先我們要創建一個簡單的Java應用程序。IbusinessLogic接口和BusinessLogic類為Spring框架中的bean提供了簡易構件塊。雖然該接口對于我們的簡單應用程序邏輯來說不是必需的,但是它是Spring框架所推薦的良好實踐。
public interface IBusinessLogic { public void foo(); } public class BusinessLogic implements IBusinessLogic { public void foo() { System.out.println( "Inside BusinessLogic.foo()"); } }
可以編寫MainApplication類,借此練習BusinessLogic bean的公有方法。
import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; public class MainApplication { public static void main(String [] args) { // Read the configuration file ApplicationContext ctx = new FileSystemXmlApplicationContext( "springconfig.xml"); //Instantiate an object IBusinessLogic testObject = (IBusinessLogic) ctx.getBean("businesslogicbean"); // Execute the public // method of the bean testObject.foo(); } }
在BusinessLogic類及其關聯接口中沒有什么需要注意的。但是,MainApplication類初始化BusinessLogic對象的方式很有意思。通過使用ctx.getBean("businesslogicbean")調用,MainApplication將加載和管理BusinessLogic類的bean實例的任務轉交給了Spring框架。
允許Spring控制BusinessLogic bean的初始化,這使得Spring運行時有機會在bean被返回給應用程序之前執行J2EE系統所需的所有與bean相關的管理任務。然后Spring運行時配置可以決定對bean應用哪些任務和模塊。該配置信息由一個XML文件提供,類似于下面所示的:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <!-- Bean configuration --> <bean id="businesslogicbean" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>IBusinessLogic</value> </property> <property name="target"> <ref local="beanTarget"/> </property> </bean> <!-- Bean Classes --> <bean id="beanTarget" class="BusinessLogic"/> </beans>
該配置文件,即springconfig.xml,指定要加載一個接口與IbusinessLogic相匹配的bean。該bean隨后被關聯到BusinessLogic實現類。看起來好像是費了很大力氣只為了加載一個簡單的bean并調用一個方法,但是您要知道,這個配置文件只是使Spring框架可以透明地對應用程序應用其組件的眾多特性的一個體現。
圖1顯示了基本的順序圖:MainApplication原樣執行,沒有應用方面。
圖1.沒有對BusinessLogic bean應用方面時的順序圖
請查看本文末尾處的參考資料,獲取這個簡單Spring應用程序的源代碼。
應用方法跟蹤(Method Tracing)方面
可能最基本的方面就是方法跟蹤方面了。這可能是您找得到的最簡單的方面了,因此它是研究新的AOP實現的一個很好的起點。
方法跟蹤方面在一個目標應用程序內捕獲對所跟蹤的方法的調用以及方法的返回值,并以某種方式顯示這種信息。在AOP中,通知的before和after類型用于捕獲這些類型的聯結點,因為這兩種通知可以在方法調用聯結點之前或之后觸發。使用Spring框架,方法跟蹤方面的before通知是在TracingBeforeAdvice類中聲明的。
import java.lang.reflect.Method; import org.springframework.aop. MethodBeforeAdvice; public class TracingBeforeAdvice implements MethodBeforeAdvice { public void before(Method m, Object[] args, Object target) throws Throwable { System.out.println( "Hello world! (by " + this.getClass().getName() + ")"); } }
類似地,after通知可以在TracingAfterAdvice類中聲明。
import java.lang.reflect.Method; import org.springframework.aop.AfterReturningAdvice; public class TracingAfterAdvice implements AfterReturningAdvice { public void afterReturning(Object object, Method m, Object[] args, Object target) throws Throwable { System.out.println( "Hello world! (by " + this.getClass().getName() + ")"); } }
這兩個類都通過實現Spring框架的適當通知接口而表示了特定的通知。每種類型的通知都指定實現before(..)或afterReturning(..)方法,以便使Spring運行時可以告訴通知適當的聯結點會在何時出現。值得注意的是,TracingAfterAdvice實際上是從AfterReturningAdvice擴展而來的,表示只有在聯結點在無異常的情況下獲得返回值時才運行通知。
為了將通知與應用程序中的適當聯結點關聯起來,必須對springconfig.xml進行一些修改。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <!-- Bean configuration --> <bean id="businesslogicbean" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>IBusinessLogic</value> </property> <property name="target"> <ref local="beanTarget"/> </property> <property name="interceptorNames"> <list> <value>theTracingBeforeAdvisor</value> <value>theTracingAfterAdvisor</value> </list> </property> </bean> <!-- Bean Classes --> <bean id="beanTarget" class="BusinessLogic"/> <!-- Advisor pointcut definition for before advice --> <bean id="theTracingBeforeAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice"> <ref local="theTracingBeforeAdvice"/> </property> <property name="pattern"> <value>.*</value> </property> </bean> <!-- Advisor pointcut definition for after advice --> <bean id="theTracingAfterAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice"> <ref local="theTracingAfterAdvice"/> </property> <property name="pattern"> <value>.*</value> </property> </bean< <!-- Advice classes --> <bean id="theTracingBeforeAdvice" class="TracingBeforeAdvice"/> <bean id="theTracingAfterAdvice" class="TracingAfterAdvice"/> </beans>
theTracingBeforeAdvisor和theTracingAfterAdvisor advisor被添加到前面所聲明的businesslogicbean。每個advisor都可能截獲所有bean所關聯到的聯結點。Advisor本身就是bean,而它唯一的作用就是將切入點定義與通知bean關聯起來。本例中的切入點定義是在靜態對象層次結構中指定相關聯結點的正則表達式。
因為本例中使用了org.springframework.aop.support.RegexpMethodPointcutAdvisor切入點advisor,切入點邏輯是使用正則表達式指定的。正則表達式用于識別公有接口對IbusinessLogici接口的聯結點。下面是一些可以用來指定IBusinessLogic接口上的不同聯結點集合的正則表達式例子:
- <value>.*</value>:該表達式選擇advisor所關聯到的一個或多個bean上的所有聯結點。
- <value>./IBusinessLogic/.foo</value>:該表達式只選擇IbusinessLogic接口上的foo()方法的聯結點。如果是advisor所關聯到的bean,則該表達式只選擇IBusinessLogic接口上的聯結點。
springconfig.xml文件中最后的bean聲明指定實現通知bean的類。
既然已經指定了跟蹤方面的正確配置,那么下一次執行MainApplication時,這些方面就會在初始化過程中被編織進去,而BusinessLogic bean中的所有方法都將被跟蹤,如圖2所示。
圖2. 方法跟蹤方面應用到BusinessLogic bean之后的順序圖(單擊圖像查看大圖)
方法跟蹤方面和例子應用程序的源代碼可在本文末尾的參考資料小節進行下載。
方面的重用
可以對方法跟蹤方面進行擴展,提供一個稍微復雜的記錄(Logging)方面。記錄方面提供了一個很不錯的重用例子,因為記錄方面所需的許多特性都已經包含在方法跟蹤方面中了。
在本例中,記錄方面擴展了方法跟蹤方面,以便顯示附加的與(在應用程序的執行過程中)所引發的異常有關的信息。
要完全使用記錄方面,需要對應用程序做一些更改。BusinessLogicException異常類提供了一個可以由IBusinessLogicInterface接口和BusinessLogic實現類新增的void bar()方法引發的異常。
public class BusinessLogicException extends Exception { } public interface IBusinessLogic { public void foo(); public void bar() throws BusinessLogicException; } public class BusinessLogic implements IBusinessLogic { public void foo() { System.out.println( "Inside BusinessLogic.foo()"); } public void bar() throws BusinessLogicException { System.out.println( "Inside BusinessLogic.bar()"); throw new BusinessLogicException(); } }
MainApplication類現在將對void bar()方法進行一次額外的調用,并處理選中的、可能由該方法引發的異常。
import org.springframeworkcontext.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; public class MainApplication { public static void main(String [] args) { // Read the configuration file ApplicationContext ctx = new FileSystemXmlApplicationContext( "springconfig.xml"); //Instantiate an object IBusinessLogic testObject = (IBusinessLogic) ctx.getBean( "businesslogicbean"); //Execute the public methods of the bean testObject.foo(); try { testObject.bar(); } catch(BusinessLogicException ble) { System.out.println( "Caught BusinessLogicException"); } } }
來自方法跟蹤方面的TracingBeforeAdvice和TracingAfterAdvice通知可以整體重用。LoggingThrowsAdvice類為新的異常記錄提供了通知。
import org.springframework.aop.ThrowsAdvice; import java.lang.reflect.Method; public class LoggingThrowsAdvice implements ThrowsAdvice { public void afterThrowing(Method method, Object[] args, Object target, Throwable subclass) { System.out.println( "Logging that a " + subclass + "Exception was thrown."); } }
應用記錄方面的最后一步是修改springconfig.xml配置文件,使其包含新添加的LoggingThrowsAdvice通知。
圖3顯示了運行MainApplication并使用Spring框架應用了記錄方面的UML順序圖。
圖3. 記錄方面應用到BusinessLogic bean之后的順序圖(單擊圖像查看大圖)
此處的記錄方面清楚地說明了如何重用現有方面以及如何在Spring框架中使用通知的throws形式。通過為before和after通知聲明新的通知來重寫現有的方法跟蹤方面實現,可以實現更復雜的記錄方面,記錄到更復雜的記錄框架,比如LOG4J。關于記錄方面和例子應用程序的源代碼,請參見本文末尾的參考資料小節。
結束語
本文展示了使用Spring框架中的基本AOP結構所應用的一些簡單方面。在本系列的下一篇文章中,我們將介紹一些更實用的方面,探討方面的生命周期,使用Spring框架的around通知,并使用Spring來應用AOP模式。
參考資料
原文出處:An Introduction to Aspect-Oriented Programming with the Spring Framework, Part 1http://www.onjava.com/pub/a/onjava/2004/07/14/springaop.html

?作者簡介 | |
Russell Miles是General Dynamics UK公司的一名軟件工程師,他負責Java和分布式系統,但是他目前主要的興趣在面向方面領域,尤其是AspectJ。 |