天天看點

Spring AOP之XML配置

1. 配置切面

因為切面Bean可以當成一個普通的SpringBean來配置,是以完全可以為該切面Bean配置依賴注入。當切面Bean定義完成後,通過<aop:aspect…/>元素中使用ref屬性來引用該Bean,就可以将該Bean轉換成一個切面Bean了。配置<aop:aspect…/>元素時可以指定如下三個屬性。

1)        id:定義該切面的辨別名

2)        ref:用于将ref屬性所引用的普通Bean轉換為切面Bean

3)        order:指定該切面Bean的優先級。

如下的配置片段定義了一個切面:

<aop:config>
		<!-- 将fourAdviceBean轉換成切面Bean
			切面Bean的新名稱為:fourAdviceAspect
			指定該切面的優先級為2 -->
		<aop:aspect id="fourAdviceAspect" ref="fourAdviceBean"
			order="2">
			……..
		</aop:aspect>
	</aop:config>
  <bean id=” fourAdviceAspect” class=”com.owen. fourAdviceAspect”/>
           

2. 配置增強處理

使用XML配置增強處理分别依賴于如下幾個元素:

1)        <aop:before…/>:配置Before增強處理

2)        <aop:after…/>:配置After增強處理

3)        <aop:after-returning../>:配置AfterReturning增強

4)        <aop:after-throwing…/>:配置AfterThrowing增強

5)        <aop:around../>配置Around增強處理

上面這些元素都不支援使用子元素,但通常可指定如下的屬性:

1)        pointcut:該屬性指定一個切入元素表達式,Spring将在比對表達式的連接配接點時織入該增強處理。

2)        method:該屬性指定一個方法名,指定将切面Bean的該方法轉換為增強處理。

3)        pointcut-ref:該屬性指定一個已經存在的切點名稱,通常pointcut和pointcut-ref兩個屬性隻需使用其中之一。

4)        throwing:該屬性隻對<after-throwing../>元素有效,用于指定一個形參名,AfterThrowing增強處理方法通過該形參通路目标方法所抛出的異常。

5)        returning:該屬性隻對<after-returning…/>元素有效,用于指定一個形參名,AfterReturning增強處理方法可通過該形參通路方法的傳回值。

3. 例子

1)        下面定義一個簡單的切面類。

public class FourAdviceTest
{
	public Object processTx(ProceedingJoinPoint jp)
		throws java.lang.Throwable
	{
		System.out.println("Around增強:執行目标方法之前,模拟開始事務...");
		// 通路執行目标方法的參數
		Object[] args = jp.getArgs();
		// 當執行目标方法的參數存在,
		// 且第一個參數是字元串參數
		if (args != null && args.length > 0
			&& args[0].getClass() == String.class)
		{
			// 修改目标方法調用參數的第一個參數
			args[0] = "【增加的字首】" + args[0];
		}
		//執行目标方法,并儲存目标方法執行後的傳回值
		Object rvt = jp.proceed(args);
		System.out.println("Around增強:執行目标方法之後,模拟結束事務...");
		// 如果rvt的類型是Integer,将rvt改為它的平方
		if(rvt != null && rvt instanceof Integer)
			rvt = (Integer)rvt * (Integer)rvt;
		return rvt;
	}
	public void authority(JoinPoint jp)
	{
		System.out.println("②Before增強:模拟執行權限檢查");
		// 傳回被織入增強處理的目标方法
		System.out.println("②Before增強:被織入增強處理的目标方法為:"
			+ jp.getSignature().getName());
		// 通路執行目标方法的參數
		System.out.println("②Before增強:目标方法的參數為:"
			+ Arrays.toString(jp.getArgs()));
		// 通路被增強處理的目标對象
		System.out.println("②Before增強:被織入增強處理的目标對象為:"
			+ jp.getTarget());
	}
	public void log(JoinPoint jp , Object rvt)
	{
		System.out.println("AfterReturning增強:擷取目标方法傳回值:"
			+ rvt);
		System.out.println("AfterReturning增強:模拟記錄日志功能...");
		// 傳回被織入增強處理的目标方法
		System.out.println("AfterReturning增強:被織入增強處理的目标方法為:"
			+ jp.getSignature().getName());
		// 通路執行目标方法的參數
		System.out.println("AfterReturning增強:目标方法的參數為:"
			+ Arrays.toString(jp.getArgs()));
		// 通路被增強處理的目标對象
		System.out.println("AfterReturning增強:被織入增強處理的目标對象為:"
			+ jp.getTarget());
	}
	public void release(JoinPoint jp)
	{
		System.out.println("After增強:模拟方法結束後的釋放資源...");
		// 傳回被織入增強處理的目标方法
		System.out.println("After增強:被織入增強處理的目标方法為:"
			+ jp.getSignature().getName());
		// 通路執行目标方法的參數
		System.out.println("After增強:目标方法的參數為:"
			+ Arrays.toString(jp.getArgs()));
		// 通路被增強處理的目标對象
		System.out.println("After增強:被織入增強處理的目标對象為:"
			+ jp.getTarget());
	}
}
           

2)        除了上面的,再定義一個簡單的切面類。

public class SecondAdviceTest
{
	// 定義Before增強處理
	public void authority(String aa)
	{
		System.out.println("目标方法的參數為:" + aa);
		System.out.println("①号Before增強:模拟執行權限檢查");
	}
}
           

3)        在Spring配置檔案中配置。

<?xml version="1.0" encoding="GBK"?>
<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-4.0.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
	<aop:config>
		<!-- 将fourAdviceBean轉換成切面Bean
			切面Bean的新名稱為:fourAdviceAspect
			指定該切面的優先級為2 -->
		<aop:aspect id="fourAdviceAspect" ref="fourAdviceBean"
			order="2">
			<!-- 定義一個After增強處理,
				直接指定切入點表達式
				以切面Bean中的release()方法作為增強處理方法 -->
			<aop:after pointcut="execution(* com.owenapp.service.impl.*.*(..))" 
				method="release"/>
			<!-- 定義一個Before增強處理,
				直接指定切入點表達式
				以切面Bean中的authority()方法作為增強處理方法 -->
			<aop:before pointcut="execution(* com.owenapp.service.impl.*.*(..))" 
				method="authority"/>
			<!-- 定義一個AfterReturning增強處理,
				直接指定切入點表達式
				以切面Bean中的log()方法作為增強處理方法 -->
			<aop:after-returning pointcut="execution(* com.owenapp.service.impl.*.*(..))" 
				method="log" returning="rvt"/>
			<!-- 定義一個Around增強處理,
				直接指定切入點表達式
				以切面Bean中的processTx()方法作為增強處理方法 -->
			<aop:around pointcut="execution(* com.owenapp.service.impl.*.*(..))" 
				method="processTx"/>
		</aop:aspect>

		<!-- 将secondAdviceBean轉換成切面Bean
			切面Bean的新名稱為:secondAdviceAspect
			指定該切面的優先級為1,該切面裡的增強處理将被優先織入 -->
		<aop:aspect id="secondAdviceAspect" ref="secondAdviceBean"
			order="1">
			<!-- 定義一個Before增強處理,
				直接指定切入點表達式
				以切面Bean中的authority()方法作為增強處理方法 
				且該參數必須為String類型(由authority方法聲明中msg參數的類型決定) -->
			<aop:before pointcut=
			"execution(* com.owenapp.service.impl.*.*(..)) and args(aa)" 
				method="authority"/>
		</aop:aspect>
	</aop:config>
	<!-- 定義一個普通Bean執行個體,該Bean執行個體将被作為Aspect Bean -->
	<bean id="fourAdviceBean"
		class="com.owenapp.aspect.FourAdviceTest"/>
	<!-- 再定義一個普通Bean執行個體,該Bean執行個體将被作為Aspect Bean -->
	<bean id="secondAdviceBean"
		class="com.owenapp.aspect.SecondAdviceTest"/>
	<bean id="hello" class="com.owenapp.service.impl.HelloImpl"/>
	<bean id="world" class="com.owenapp.service.impl.WorldImpl"/>
</beans>
           

完成上面的定義後,運作上面的示例程式,将看到使用XML配置檔案來管理切面、增強處理的效果。

4. 配置切入點

配置切入點,我們需要配置<aop:pointcut…/>元素,這裡需要指定下面的屬性:

1)        id:指定該切點的辨別名。

2)        exception:指定該切點關聯的切入點表達式。

下面筆者定義一個AfterThrowing增強處理,包含該增強處理的切面類如下:

public class RepairAspect
{
	// 定義一個普通方法作為Advice方法
	// 形參ex用于通路目标方法中抛出的異常
	public void doRecoveryActions(Throwable ex)
	{
		System.out.println("目标方法中抛出的異常:" + ex);
		System.out.println("模拟Advice對異常的修複...");
	}
}
           

下面的配置檔案将負責配置該Bean執行個體,并将該Bean執行個體轉換成切面Bean。

<?xml version="1.0" encoding="GBK"?>
<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-4.0.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
	<aop:config>
		<!-- 定義一個切入點:myPointcut
			通過expression指定它對應的切入點表達式 -->
		<aop:pointcut id="myPointcut" 
			expression="execution(* com.owen.app.service.impl.*.*(..))"/>
		<aop:aspect id="afterThrowingAdviceAspect"
			ref="afterThrowingAdviceBean">
			<!-- 定義一個AfterThrowing增強處理,指定切入點
				以切面Bean中的doRecoveryActions()方法作為增強處理方法 -->
			<aop:after-throwing pointcut-ref="myPointcut" 
				method="doRecoveryActions" throwing="ex"/>
		</aop:aspect>
	</aop:config>
	<!-- 定義一個普通Bean執行個體,該Bean執行個體将被作為Aspect Bean -->
	<bean id="afterThrowingAdviceBean"
		class="com.owen.app.aspect.RepairAspect"/>
	<bean id="hello" class="com.owen.app.service.impl.HelloImpl"/>
	<bean id="world" class="com.owen.app.service.impl.WorldImpl"/>
</beans>
           

上面配置了一個myPontcut,這校準其他切面Bean就可多次複用該切點了。上面的配置檔案在配置<aop:pointcut../>元素時,使用point-ref引用了一個已有的切入點。