1. 程式人生 > >spring aop advice註解實現的幾種方式

spring aop advice註解實現的幾種方式

spring的aop advice(可以理解為切面上的邏輯)用註解來實現有五種實現方式:

  1. @Before(execution) 在方法執行前攔
  2. @AfterReturning(execution)在方法正常return結束後攔截
  3. @AfterThrowing(execution) 在方法丟擲異常時攔截
  4. @After(execution) 在方法結束後攔截,無論正常結束還是異常結束
  5. @Around(execution)唯一可以使用ProceedingJoinPoint引數來控制流程的advice,在方法執行前攔截,可以在切面邏輯中手動釋放攔截,且可以在其後加入邏輯程式碼,該程式碼段會在方法執行後執行.

這幾種方式如果同時存在 , 會有一個先後順序,下邊測試後可以從列印結果中很明顯地看到,但是一般情況下,儘量避免用這種先後順序的方式來決定切面邏輯的設計,如果切面邏輯很複雜,可以用@Around整合在一起.

注意 : “表示式(execution)” 匹配到的方法必須為interface的實現類才可以,否則會丟擲以下異常:Cannot proxy target class because CGLIB2 is not available.
如果一個類實現了介面 , spring就會通過jdk自帶的Proxy 和 InvocationHandler自動生成代理 , 如果沒有實現介面, 需要依賴cglib包 , 以直接操作二進位制碼的方式 , 來生成代理程式碼.
可以將獲取到物件的class打印出來,可以很明顯看到其中有”$$EnhancerByCGLIB”的字樣,它是一個代理物件.

另外 , 測試中出現一個問題 , PointCut() 無法正常呼叫, 後來發現是aspectjrt 版本的問題 ,因為是跟著馬士兵老師的視訊走的 , 所以用的spring 2.5.6 的版本 , 我用pom構建專案的, spring2.5.6中整合的aspectjrt是1.6.1 版本的 , 這個版本和jdk1.7有衝突 , 將版本更換為新版的1.8.7就好了

下邊上程式碼:

切面類:

@Aspect
@Component
public class LogInterceptor {

    //advice 切點語法規則,方法體不執行,其他advice可以直接將該方法作為引數
    //按照該語法來執行攔截
@Pointcut("execution(* com.pindao.nine.dao.UserDao.show* (..))") public void pointCut1(){ System.out.println("this is pointCut"); } //攔截在方法執行之前 @Before("pointCut1()") public void before(){ System.out.println("method start..."); } //攔截在方法體執行之後,無論正常執行結束或異常結束 @After("execution(* com.pindao.nine.dao.UserDao.show* (..))") public void after(){ System.out.println("method end!"); } //攔截在方法正常return之後 @AfterReturning(value = "pointCut1()") public void afterReturn(){ System.out.println("this is afterReturing pointcut!"); } //攔截在方法丟擲異常之後 @AfterThrowing("pointCut1()") public void afterThrowing(){ System.out.println("this is afterThrowing pointcut!"); } //攔截在方法體執行之前,插入程式碼,需要手動釋放攔截,並且可以在繼續執行之後插入程式碼 //ProceedingJoinPoint 引數只能在@Around下用,在其他advice下用,會丟擲異常 @Around("pointCut1()") public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("this is around pointcut start..!"); //攔截結束,程式繼續執行, 繼續下一個攔截或者進行正常邏輯程式碼 Object obj = pjp.proceed(); System.out.println("this is around pointcut end..!"); return obj; } }

執行切面的bean():

@Component("userDao")
public class UserDaoImpl implements UserDao {
    public void showUser() {
        System.out.println("this is the real method start...");
//        int i = 1/0;
        System.out.println("this is the real method end");
        return 0;
    }
}

spring啟用註解和切面配置 beans.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

       <context:annotation-config />
       <context:component-scan base-package="com.pindao.nine" />
<!--aspectj是一個面向切面的框架,spring的aop,是基於aspectj來實現的-->       
       <aop:aspectj-autoproxy />

</beans>

手動啟動spring容器,呼叫showUser()方法:

@Test
public void testShowUserDao() throws Exception {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    UserDao userDao = (UserDao) context.getBean("userDao");
    int result = userDao.showUser();
    System.out.println(result);
}

執行結果:
1. 正常流程:

method start...
this is around pointcut start..!
this is the real method start...
this is the real method end
method end!
this is afterReturing pointcut!
this is around pointcut end..!
0

2.方法體丟擲異常流程:

method start...
this is around pointcut start..!
this is the real method start...
method end!
this is afterThrowing pointcut!
java.lang.ArithmeticException: / by zero ......

下邊是maven依賴:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>2.5.6</version>
    <exclusions>
        <exclusion>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>2.5.6</version>
    <exclusions>
        <exclusion>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.7</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.7</version>
</dependency>
<!-- cglib通過二進位制的方式生成代理類 -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.0</version>
</dependency>