1. 程式人生 > >Spring使用AspectJ開發AOP:基於XML

Spring使用AspectJ開發AOP:基於XML

基於XML的宣告式

基於 XML 的宣告式是指通過 Spring 配置檔案的方式定義切面、切入點及宣告通知,而所有的切面和通知都必須定義在 <aop:config> 元素中。

下面通過案例演示 Spring 中如何使用基於 XML 的宣告式實現 AOP 的開發。

1. 匯入 JAR 包

使用 AspectJ 除了需要匯入 Spring AOP 的 JAR 包以外,還需要匯入與 AspectJ 相關的 JAR 包,具體如下。

  • spring-aspects-3.2.13.RELEASE.jar:Spring 為 AspectJ 提供的實現,在 Spring 的包中已經提供。
  • com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar:是 AspectJ 提供的規範,可以在官方網址https://repo.spring.io/webapp/#/search/quick/ 中搜索並下載。

2. 建立切面類 MyAspect

在 src 目錄下建立一個名為 com.mengma.aspectj.xml 的包,在該包下建立切面類 MyAspect,編輯後如下所示。

package com.mengma.aspectj.xml;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

//切面類
public class MyAspect {
// 前置通知
public void myBefore(JoinPoint joinPoint) {
System.out.print("前置通知,目標:");
System.out.print(joinPoint.getTarget() + "方法名稱:");
System.out.println(joinPoint.getSignature().getName());
}

// 後置通知
public void myAfterReturning(JoinPoint joinPoint) {
System.out.print("後置通知,方法名稱:" + joinPoint.getSignature().getName());
}

// 環繞通知
public Object myAround(ProceedingJoinPoint proceedingJoinPoint)
throws Throwable {
System.out.println("環繞開始"); // 開始
Object obj = proceedingJoinPoint.proceed(); // 執行當前目標方法
System.out.println("環繞結束"); // 結束
return obj;
}

// 異常通知
public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
System.out.println("異常通知" + "出錯了" + e.getMessage());
}

// 最終通知
public void myAfter() {
System.out.println("最終通知");
}
}

 

上述程式碼中,分別定義了幾種不同的通知型別方法,在這些方法中,通過 JoinPoint 引數可以獲得目標物件的類名、目標方法名和目標方法引數等。需要注意的是,環繞通知必須接收一個型別為 ProceedingJoinPoint 的引數,返回值必須是 Object 型別,且必須丟擲異常。異常通知中可以傳入 Throwable 型別的引數,用於輸出異常資訊。

3. 建立 Spring 配置檔案

在 com.mengma.aspectj.xml 包下建立 applicationContext.xml 的配置檔案,如下所示。

<?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-2.5.xsd 
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!--目標類 -->
<bean id="customerDao" class="com.mengma.dao.CustomerDaoImpl" />
<!--切面類 -->
<bean id="myAspect" class="com.mengma.aspectj.xml.MyAspect"></bean>
<!--AOP 程式設計 -->
<aop:config>
<aop:aspect ref="myAspect">
<!-- 配置切入點,通知最後增強哪些方法 -->
<aop:pointcut expression="execution ( * com.mengma.dao.*.* (..))"
id="myPointCut" />
<!--前置通知,關聯通知 Advice和切入點PointCut -->
<aop:before method="myBefore" pointeut-ref="myPointCut" />
<!--後置通知,在方法返回之後執行,就可以獲得返回值returning 屬性 -->
<aop:after-returning method="myAfterReturning"
pointcut-ref="myPointCut" returning="returnVal" />
<!--環繞通知 -->
<aop:around method="myAround" pointcut-ref="myPointCut" />
<!--丟擲通知:用於處理程式發生異常,可以接收當前方法產生的異常 -->
<!-- *注意:如果程式沒有異常,則不會執行增強 -->
<!-- * throwing屬性:用於設定通知第二個引數的名稱,型別Throwable -->
<aop:after-throwing method="myAfterThrowing"
pointcut-ref="myPointCut" throwing="e" />
<!--最終通知:無論程式發生任何事情,都將執行 -->
<aop:after method="myAfter" pointcut-ref="myPointCut" />
</aop:aspect>
</aop:config>
</beans>

 

上述程式碼中,首先在第 4、7、8 行程式碼中分別匯入了 AOP 的名稱空間。第 12 行程式碼指定了切面類。

第 17、18 行程式碼配置了切入點,通知需要增強哪些方法,expression="execution(*com.mengma.dao.*.*(..))的意思是增強 com.mengma.dao 包下所有的方法。

第 20~32 行程式碼用於關聯通知(Advice)和切入點(PointCut)。以第 20 行程式碼前置通知為例,<aop:before> 標籤的 method 屬性用於指定通知,pointcut-ref 屬性用於指定切入點,也就是要增強的方法,其他幾種通知的配置可以參考程式碼註釋。

4. 建立測試類

在 com.mengma.aspectj.xml 包下建立測試類 XMLTest,如下所示。

package com.mengma.aspectj.xml;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mengma.dao.CustomerDao;

public class XMLTest {
@Test
public void test() {
String xmlPath = "com/mengma/aspectj/xml/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
xmlPath);
// 從spring容器獲取例項
CustomerDao customerDao = (CustomerDao) applicationContext
.getBean("customerDao");
// 執行方法
customerDao.add();
}
}

 

5. 執行專案並檢視結果

使用 JUnit 測試執行 test() 方法,執行成功後,控制檯的輸出結果如圖 1 所示。


圖 1  執行結果


為了更好地演示異常通知,接下來在 CustomerDaoImpl 類的 add() 方法中新增一行會丟擲異常的程式碼,如“int i=1/0;”,重新執行 XMLTest 測試類,可以看到異常通知執行了,此時控制檯的輸出結果如圖 2 所示。


圖 2  執行結果


從圖 1 和圖 2 的輸出結果中可以看出,基於 XML 宣告式的 AOP 開發已經成功實