Spring AOP實現


Spring支援使用@AspectJ注釋樣式方法和基於模式的方法來實現自定義方面。

基於XML模式

方面(Aspects)使用常規類以及基於XML的組態來實現。
要使用本節中描述的aop名稱空間標籤,您需要按照以下所述匯入spring-aop模式:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

   <!-- bean definition & AOP specific configuration -->

</beans>

宣告一個方面(Aspects)

使用<aop:aspect>元素宣告一個方面(Aspects),並使用ref屬性參照後台bean,如下所示:

<aop:config>
   <aop:aspect id="myAspect" ref="aBean">
   ...
   </aop:aspect>
</aop:config>

<bean id="aBean" class="...">
...
</bean>

這個「aBean」將被組態和依賴注入就像任何其他的Spring Bean一樣,就像在前幾章中看到的一樣。

宣告一個切入點

切入點(pointcut)有助於確定要用不同建議執行的關聯點(即方法)。 在使用基於XML模式的組態時,切入點將定義如下:

<aop:config>
   <aop:aspect id="myAspect" ref="aBean">

   <aop:pointcut id="businessService"
      expression="execution(* com.xyz.myapp.service.*.*(..))"/>
   ...
   </aop:aspect>
</aop:config>

<bean id="aBean" class="...">
...
</bean>

以下範例定義了一個名為「businessService」的切入點,該切入點將匹配com.yiibai包中Student類中的getName()方法的執行:

<aop:config>
   <aop:aspect id="myAspect" ref="aBean">

   <aop:pointcut id="businessService"
      expression="execution(* com.yiibai.Student.getName(..))"/>
   ...
   </aop:aspect>
</aop:config>

<bean id="aBean" class="...">
...
</bean>

宣告通知

您可以使用<aop:{ADVICE NAME}>元素在<aop:aspect>內的五個通知中的任何一個宣告如下:

<aop:config>
   <aop:aspect id="myAspect" ref="aBean">
      <aop:pointcut id="businessService"
         expression="execution(* com.xyz.myapp.service.*.*(..))"/>

      <!-- a before advice definition -->
      <aop:before pointcut-ref="businessService" 
         method="doRequiredTask"/>

      <!-- an after advice definition -->
      <aop:after pointcut-ref="businessService" 
         method="doRequiredTask"/>

      <!-- an after-returning advice definition -->
      <!--The doRequiredTask method must have parameter named retVal -->
      <aop:after-returning pointcut-ref="businessService"
         returning="retVal"
         method="doRequiredTask"/>

      <!-- an after-throwing advice definition -->
      <!--The doRequiredTask method must have parameter named ex -->
      <aop:after-throwing pointcut-ref="businessService"
         throwing="ex"
         method="doRequiredTask"/>

      <!-- an around advice definition -->
      <aop:around pointcut-ref="businessService" 
         method="doRequiredTask"/>
   ...
   </aop:aspect>
</aop:config>

<bean id="aBean" class="...">
...
</bean>

可以對不同的通知使用相同doRequiredTask或不同的方法。 這些方法將被定義為方面模組的一部分。

基於@AspectJ

@AspectJ是指將Java方法注釋為Java 5注釋的常規Java類的方式。 @AspectJ是指將Java方法注釋為Java 5注釋的常規Java類的方式。通過在基於XML Schema的組態檔案中包含以下元素來啟用@AspectJ支援。

<aop:aspectj-autoproxy/>

宣告一個方面(aspect)

方面(aspect)的類就像任何其他正常的bean一樣,並且可以像任何其他類一樣具有方法和欄位,不過它們使用@Aspect進行註釋,如下所示:

package org.xyz;

import org.aspectj.lang.annotation.Aspect;

@Aspect
public class AspectModule {

}

它們就像任何其他以XML格式組態的bean一樣,如下所示:

<bean id="myAspect" class="org.xyz.AspectModule">
   <!-- configure properties of aspect here as normal -->
</bean>

宣告一個切入點

切入點(pointcut)有助於確定要用不同通知執行的關聯點(即方法)。 在使用基於@AspectJ的組態時,切入點宣告有兩部分:

  • 一個切入點表示式,確定哪些方法執行。
  • 切入點簽名包括名稱和任意數量的引數。 該方法的實體是無關緊要的,也可以是空的。

以下範例定義了一個名為「businessService」的切入點,該切入點將匹配com.xyz.myapp.service包下的類中可用的每個方法的執行:

import org.aspectj.lang.annotation.Pointcut;

@Pointcut("execution(* com.xyz.myapp.service.*.*(..))") // expression 
private void businessService() {}  // signature

以下範例定義了一個名為「getname」的切入點,該切入點將與com.yiibai包下的Student類中的getName()方法的執行相匹配:

import org.aspectj.lang.annotation.Pointcut;

@Pointcut("execution(* com.yiibai.Student.getName(..))") 
private void getname() {}

宣告通知

您可以使用@{ADVICE-NAME}注釋在以下所述的五個建議中宣告任何一個。假設您已經定義了一個切入點簽名方法為businessService(),參考以下組態:

@Before("businessService()")
public void doBeforeTask(){
 ...
}

@After("businessService()")
public void doAfterTask(){
 ...
}

@AfterReturning(pointcut = "businessService()", returning="retVal")
public void doAfterReturnningTask(Object retVal){
  // you can intercept retVal here.
  ...
}

@AfterThrowing(pointcut = "businessService()", throwing="ex")
public void doAfterThrowingTask(Exception ex){
  // you can intercept thrown exception here.
  ...
}

@Around("businessService()")
public void doAroundTask(){
 ...
}

可以為任何通知定義切入點內嵌。 下面是一個為之前通知定義的內聯切入點的範例:

@Before("execution(* com.xyz.myapp.service.*.*(..))")
public doBeforeTask(){
 ...
}