Spring AOP+AspectJ註解範例


在本教學中,我們將向你展示如何將AspectJ註解整合到Spring AOP框架。在這個Spring AOP+ AspectJ 範例中,讓您輕鬆實現攔截方法。
常見AspectJ的註解:
  1. @Before – 方法執行前執行
  2. @After – 執行在方法返回結果後
  3. @AfterReturning – 執行在方法返回一個結果後,在攔截器返回結果。
  4. @AfterThrowing – 執行方法在丟擲異常後,
  5. @Around – 圍繞方法執行執行,結合以上這三個通知。
注意
Spring AOP 中沒有 AspectJ 支援,請閱讀 內建 Spring AOP 例子

1. 目錄結構

看到這個例子的目錄結構。

2. Spring Beans

普通 bean 中有幾個方法,後來通過 AspectJ 註解攔截。
package com.yiibai.customer.bo;

public interface CustomerBo {

	void addCustomer();
	
	String addCustomerReturnValue();
	
	void addCustomerThrowException() throws Exception;
	
	void addCustomerAround(String name);
}
package com.yiibai.customer.bo.impl;

import com.yiibai.customer.bo.CustomerBo;

public class CustomerBoImpl implements CustomerBo {

	public void addCustomer(){
		System.out.println("addCustomer() is running ");
	}
	
	public String addCustomerReturnValue(){
		System.out.println("addCustomerReturnValue() is running ");
		return "abc";
	}
	
	public void addCustomerThrowException() throws Exception {
		System.out.println("addCustomerThrowException() is running ");
		throw new Exception("Generic Error");
	}
	
	public void addCustomerAround(String name){
		System.out.println("addCustomerAround() is running, args : " + name);
	}
}

4. 啟用AspectJ

在 Spring 組態檔案,把「<aop:aspectj-autoproxy />」,並定義Aspect(攔截)和普通的bean。

File : applicationContext.xml

<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 ">

	<aop:aspectj-autoproxy />

	<bean id="customerBo" class="com.yiibai.customer.bo.impl.CustomerBoImpl" />

	<!-- Aspect -->
	<bean id="logAspect" class="com.yiibai.aspect.LoggingAspect" />

</beans>

4. AspectJ @Before

在下面例子中,logBefore()方法將在 customerBo介面的 addCustomer()方法的執行之前被執行。
AspectJ的「切入點」是用來宣告哪種方法將被攔截,應該參考Spring AOP切入點指南,支援切入點表示式的完整列表。

File : LoggingAspect.java

package com.yiibai.aspect;

import org.aspectj.lang.JoinYiibai;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class LoggingAspect {

	@Before("execution(* com.yiibai.customer.bo.CustomerBo.addCustomer(..))")
	public void logBefore(JoinYiibai joinYiibai) {

		System.out.println("logBefore() is running!");
		System.out.println("hijacked : " + joinYiibai.getSignature().getName());
		System.out.println("******");
	}

}

執行

CustomerBo customer = (CustomerBo) appContext.getBean("customerBo");
customer.addCustomer();

輸出結果

logBefore() is running!
hijacked : addCustomer
******
addCustomer() is running

5. AspectJ @After

在下面例子中,logAfter()方法將在 customerBo 介面的 addCustomer()方法的執行之後執行。

File : LoggingAspect.java

package com.yiibai.aspect;

import org.aspectj.lang.JoinYiibai;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;

@Aspect
public class LoggingAspect {

	@After("execution(* com.yiibai.customer.bo.CustomerBo.addCustomer(..))")
	public void logAfter(JoinYiibai joinYiibai) {

		System.out.println("logAfter() is running!");
		System.out.println("hijacked : " + joinYiibai.getSignature().getName());
		System.out.println("******");

	}

}

執行它

CustomerBo customer = (CustomerBo) appContext.getBean("customerBo");
customer.addCustomer();

輸出結果

addCustomer() is running 
logAfter() is running!
hijacked : addCustomer
******

6. AspectJ @AfterReturning

在下面例子中,logAfterReturning()方法將在 customerBo 介面的addCustomerReturnValue()方法執行之後執行。此外,還可以擷取返回的值使用「returning」屬性。

要擷取返回的值,對「returning」屬性(結果)的值必須用相同的方法引數(結果)。

File : LoggingAspect.java

package com.yiibai.aspect;

import org.aspectj.lang.JoinYiibai;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;

@Aspect
public class LoggingAspect {

   @AfterReturning(
      pointcut = "execution(* com.yiibai.customer.bo.CustomerBo.addCustomerReturnValue(..))",
      returning= "result")
   public void logAfterReturning(JoinYiibai joinYiibai, Object result) {

	System.out.println("logAfterReturning() is running!");
	System.out.println("hijacked : " + joinYiibai.getSignature().getName());
	System.out.println("Method returned value is : " + result);
	System.out.println("******");
   }
}

執行它

CustomerBo customer = (CustomerBo) appContext.getBean("customerBo");
	customer.addCustomerReturnValue();

輸出結果

addCustomerReturnValue() is running 
logAfterReturning() is running!
hijacked : addCustomerReturnValue
Method returned value is : abc
******

7. AspectJ @AfterReturning

在下面的例子中,如果 customerBo 介面的addCustomerThrowException()方法丟擲異常logAfterThrowing()方法將被執行。

File : LoggingAspect.java

package com.yiibai.aspect;

import org.aspectj.lang.JoinYiibai;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;

@Aspect
public class LoggingAspect {

   @AfterThrowing(
      pointcut = "execution(* com.yiibai.customer.bo.CustomerBo.addCustomerThrowException(..))",
      throwing= "error")
    public void logAfterThrowing(JoinYiibai joinYiibai, Throwable error) {

	System.out.println("logAfterThrowing() is running!");
	System.out.println("hijacked : " + joinYiibai.getSignature().getName());
	System.out.println("Exception : " + error);
	System.out.println("******");

    }
}

執行它

CustomerBo customer = (CustomerBo) appContext.getBean("customerBo");
customer.addCustomerThrowException();

輸出結果

addCustomerThrowException() is running 
logAfterThrowing() is running!
hijacked : addCustomerThrowException
Exception : java.lang.Exception: Generic Error
******
Exception in thread "main" java.lang.Exception: Generic Error
	//...

8. AspectJ @Around

在下面例子中,logAround()方法將在customerBo介面的addCustomerAround()方法執行之前執行, 必須定義「joinYiibai.proceed();」 控制何時攔截器返回控制到原來的addCustomerAround()方法。

File : LoggingAspect.java

package com.yiibai.aspect;

import org.aspectj.lang.ProceedingJoinYiibai;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;

@Aspect
public class LoggingAspect {

   @Around("execution(* com.yiibai.customer.bo.CustomerBo.addCustomerAround(..))")
   public void logAround(ProceedingJoinYiibai joinYiibai) throws Throwable {

	System.out.println("logAround() is running!");
	System.out.println("hijacked method : " + joinYiibai.getSignature().getName());
	System.out.println("hijacked arguments : " + Arrays.toString(joinYiibai.getArgs()));
		
	System.out.println("Around before is running!");
	joinYiibai.proceed(); //continue on the intercepted method
	System.out.println("Around after is running!");
		
	System.out.println("******");

   }
	
}

執行它

CustomerBo customer = (CustomerBo) appContext.getBean("customerBo");
customer.addCustomerAround("yiibai");

輸出結果

logAround() is running!
hijacked method : addCustomerAround
hijacked arguments : [yiibai]
Around before is running!
addCustomerAround() is running, args : yiibai
Around after is running!
******

總結

它總是建議採用最少 AspectJ 註解。這是關於Spring AspectJ 的一篇相當長的文章。進一步的解釋和例子,請存取下面的參考連結。

下載原始碼 – http://pan.baidu.com/s/1boo4f9P