1. 程式人生 > >Spring AOP各種通知 以及執行順序

Spring AOP各種通知 以及執行順序

1.定義切面

</pre><pre name="code" class="java"><pre name="code" class="java">package test2;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

// 首先我們要寫一個普通類,此類作為日誌記錄類
public class MyLog
{

	//在類裡面寫方法,方法名詩可以任意的。此處我用標準的before和after來表示  
//	訪問目標方法最簡單的做法是定義增強處理方法時將第一個引數定義為 JoinPoint 型別,當該增強處理方法被呼叫時,該 JoinPoint 引數就代表了織入增強處理的連線點。JoinPoint 裡包含了如下幾個常用方法。
	//	Object[] getArgs(): 返回執行目標方法時的引數。
	//	Signature getSignature(): 返回被增強的方法的相關資訊。
	//	Object getTarget(): 返回被織入增強處理的目標物件。
	//	Object getThis(): 返回 AOP 框架為目標物件生成的代理物件。
	//	提示:當時使用 Around 處理時,我們需要將第一個引數定義為 ProceedingJoinPoint 型別,該型別是 JoinPoint 型別的子類。。

	//	   1.環繞方法通知,環繞方法通知要注意必須給出呼叫之後的返回值,否 
	//       則被代理的方法會返回null,除非你真的打算這麼做。 
	//     2.只有環繞通知才可以使用JoinPoint的子類ProceedingJoinPoint,個 
	//      連線點型別可以呼叫代理的方法,並獲取、改變返回值。
	//	   3.返回後通知(After return advice) :在某連線點正常完成後執行的通知,不包括丟擲異常的情況。
	//	    ApplicationContext中在<aop:aspect>裡面使用<after-returning>元素進行宣告。
	//前置通知
	public void before(JoinPoint joinpoint)
	{

		System.out.println("被攔截方法(目標方法)呼叫之前,前置通知執行");
		//		Object[] args = joinpoint.getArgs(); //此方法返回的是一個數組
		//		for (int i = 0; i < joinpoint.getArgs().length; i++)
		//		{
		//			System.out.println(args[i]);
		//		}
		//System.out.println("方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
	}

	// 後通知
	public void after(JoinPoint joinpoint)
	{
<span style="white-space:pre">		</span>System.out.println("被攔截方法(目標方法)呼叫之後,後置通知立即執行執行(被攔截方法是否拋異常,都會執行)");
	}

	//環繞通知
	public Object doAround(ProceedingJoinPoint joinpoint) throws java.lang.Throwable
	{
		System.out.println("環繞通知joinpoint.proceed之前(執行目標方法之前),模擬開始事物...");
		Object rvt = joinpoint.proceed();// 執行被攔截方法(目標方法),rvt接受方法執行後的返回值  
		//		Object rvt = joinpoint.proceed(new String[] { "王五", "234" });//可對原來引數修改  原來 : "張三", "123"
		System.out.println("環繞通知joinpoint.proceed之後(執行目標方法之後),模擬結束事物...");
		return rvt + "新增的內容";//本方法可對目標方法返回值進行修改,返回後通知方法引數obj為本方法的返回值(若本方法無返回值,obj為null)
	}

	//返回後通知
	public void log(JoinPoint jp, Object obj)//若有環繞通知obj為環繞通知的返回值(環繞通知無返回值 obj為null)
	{
		System.out.println("返回後通知執行目標方法返回值:" + obj);
	}

	//丟擲異常後通知
	public void doThrowing(JoinPoint jp, Throwable ex)
	{
		System.out.println("方法:" + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName() + "丟擲異常:" + ex.getMessage());
		System.out.println();
	}
}

2.要被攔截的類

package test2;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test
{//此類中方法可以寫任意多個。我只寫一個
	public String test(String name, String pwd)
	{
		System.out.println("目標方法被呼叫:"+name+":"+pwd);
//		int i = 1 / 0;
		return name+":"+pwd;
	}

	public static void main(String[] args)
	{
		Test test = (Test) (new ClassPathXmlApplicationContext("test2/applicationContext.xml").getBean("Test"));
		test.test("張三", "123");
	}
}

3.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:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
	<bean id="MyLog" class="test2.MyLog"></bean>
	<bean id="Test" class="test2.Test"></bean>
	<aop:config>
		<aop:aspect ref="MyLog">
			<!-- 方式1:
			    <aop:pointcut id="log" expression="execution(* test2.*.*(..))" /> 
				<aop:before pointcut-ref="log" method="before" /> 
				<aop:after pointcut-ref="log" method="after" /> 
				<aop:after-throwing pointcut-ref="log" method="doThrowing" throwing="ex"/>  
			-->
			<!-- 方式2:-->
			<aop:before pointcut="execution(* test2.*.*(..))" method="before" />
			<aop:after pointcut="execution(* test2.*.*(..))" method="after" />
	                <aop:around pointcut="execution(* test2.*.*(..))" method="doAround" />
			<aop:after-returning pointcut="execution(* test2.*.*(..))" method="log" returning="obj"/>  
			<aop:after-throwing pointcut="execution(* test2.*.*(..))" method="doThrowing" throwing="ex"/> 
		</aop:aspect>
	</aop:config>
</beans>

4.執行結果:(結果描述了順序)

      目標方法無異常時:以上程式碼

      被攔截方法(目標方法)呼叫之前,前置通知執行
       環繞通知joinpoint.proceed之前(執行目標方法之前),模擬開始事物...
       目標方法被呼叫:張三:123
       被攔截方法(目標方法)呼叫之後,後置通知立即執行執行(被攔截方法是否拋異常,都會執行)
       環繞通知joinpoint.proceed之後(執行目標方法之後),模擬結束事物...
      返回後通知執行目標方法返回值:張三:123新增的內容

   目標方法有異常時:將test2.Tset  中  //int i = 1 / 0;註釋去掉

   被攔截方法(目標方法)呼叫之前,前置通知執行
   環繞通知joinpoint.proceed之前(執行目標方法之前),模擬開始事物...
   目標方法被呼叫:張三:123
   被攔截方法(目標方法)呼叫之後,後置通知立即執行執行(被攔截方法是否拋異常,都會執行)
   方法:test2.Test.test丟擲異常:/ by zero