1. 程式人生 > >Spring AOP學習筆記(一)-AOP相關概念和基於註解方式實現AOP的規則

Spring AOP學習筆記(一)-AOP相關概念和基於註解方式實現AOP的規則

一、 Spring AOP 概念

其實AOP就是要將我們Aspect中的Pointcut和Target Object中的JointPoint動態的連線起來,同時我們通過Advice指明Pointcut執行的一個時機。這是個人理解
AOP相關名詞解釋

名詞 解釋
Ascpect 橫跨多個類的模組化關注點
Pointcut 指明Aspect和哪個連線點進行連線
Advice Advice是單一橫切關注點的邏輯的載體,他代表將會織入到JointPoint的橫切邏輯;也可以說是Aspect的具體的方法
Target Object Aspect關注的物件
Joint Point 表示目標物件執行的方法

Advice 的分類

Adice種類 解釋
Before Advice 在Joint Point(執行方法)之前執行Pointcut方法)
After return Advice 在 Joint Point(執行方法)正常退出時執行Pointcut
After throwing Advice 在Joint Point(執行方法)丟擲異常退出時執行Pointcut
After Advice 在Joint Point(執行方法)退出(不管是正常退出還是拋異常退出)時執行Pointcut
Around Advice 在Joint Point(執行方法)被呼叫之前和之後都會執行Pointcut

二、註解的方式宣告一個切面

2.1、切面中涉及的註解
註解 宣告地點 使用方式
@Aspect 宣告在類上 表明這時一個Aspect
@Pointcut 宣告在Pointcut(Aspect的方法)上 指明和哪個Target Object 的Joint Point進行連線
@Before 宣告註解在Aspect的方法上 表明在Joint Point(執行方法)之前執行Aspect的方法
@AfterReturning 宣告註解在Aspect的方法上 表明在 Joint Point(執行方法)正常退出時執行Aspect的方法
@AfterThrowing 宣告註解在Aspect的方法上 表明在Joint Point(執行方法)丟擲異常退出時執行執行Aspect的方法
@After 宣告註解在Aspect的方法上 表明在Joint Point(執行方法)被呼叫之前和之後都會執行執行Aspect的方法
2.2、宣告一個Aspect
package com.zbt.day03;

import org.aspectj.lang.annotation.*;

@Aspect
public class AfterThrowingAspect {
}

在Spring上下文中配置Bean注入,因為Aspect也是一個類,需要使用注入的方式讓Spring管理一個Bean

<aop:aspectj-autoproxy/>//開啟Spring AOP自動代理功能
<bean id="audience" class="com.zbt.day01.Audience"></bean>

因為使用@AspectJ表示我們已經放棄了自動代理(auto-proxy)的方式,因此我們需要使用註解的方式@Component或者在Spring上下文中配置自動代理。

2.3、切點表示式
方法 描述
execution(public * *(..)) 執行那些方法為public的Joint Point
execution(* set*(..)) 執行那些方法名為set的Joint Point
execution(* com.xyz.service.AccountService.*(..)) 執行com.xyz.service.AccountService中所有的JointPoint(方法)
execution(* com.xyz.service.* . *(..) 執行com.xyz.service包中任何的JointPoint(方法)
execution(* com.xyz.service..* . *(..)) 執行com.xyz.service..* . *(..))包和其子包下面所有的JointPoint(方法)
within(com.xyz.service.*) 執行所有在com.xyz.service包中所有的JointPoint(方法)
this(com.xyz.service.AccountService)
target(com.xyz.service.AccoutnService) 執行實現了com.xyz.service.AccoutnService介面的所有的類的JointPoint(方法)
args(java.io.Serializable) 執行任何連結點引數只有一個,且指定引數型別為執行時Serializable(我們可以指定任意引數型別,只要是我們需要的)
@target(org.springframework.transaction.annotation.Transactional) 執行目標物件註解了@Transaction註解的方法
bean(tradeService)
bean(*Service)
2.4、宣告一個Advice

@Before

    @Before("execution(* com.zbt.day03.ThrowExceptionApp.division(..))")
    public void beforeJointPoint(){
        System.out.println("在Joint Point執行前執行此方法");
    }

@AfterThrowing

    @AfterThrowing("execution(* com.zbt.day03.ThrowExceptionApp.division(..))")
    public void printAbonormal(){
        System.out.println("在Joint Point丟擲異常後執行此方法");
    }

@AfterReturning

    @AfterReturning("execution(* com.zbt.day03.ThrowExceptionApp.division(..))")
    public void printNormal(){
        System.out.println("在Joint Point正常退出執行此方法");
    }

@After

    @After("execution(* com.zbt.day03.ThrowExceptionApp.division(..))")
    public void print(){
        System.out.println("不管Joint Point是正常退出還是異常退出都執行此方法");
    }

@Round

示例
編寫Aspect和Advice

package com.zbt.day03;

import org.aspectj.lang.annotation.*;

@Aspect
public class AfterThrowingAspect {
    @Before("execution(* com.zbt.day03.ThrowExceptionApp.division(..))")
    public void beforeJointPoint(){
        System.out.println("在Joint Point執行前執行此方法");
    }
    @AfterThrowing("execution(* com.zbt.day03.ThrowExceptionApp.division(..))")
    public void printAbonormal(){
        System.out.println("在Joint Point丟擲異常後執行此方法");
    }
    @AfterReturning("execution(* com.zbt.day03.ThrowExceptionApp.division(..))")
    public void printNormal(){
        System.out.println("在Joint Point正常退出執行此方法");
    }
    @After("execution(* com.zbt.day03.ThrowExceptionApp.division(..))")
    public void print(){
        System.out.println("不管Joint Point是正常退出還是異常退出都執行此方法");
    }
}

編寫Target Object和Joint Point(Target 中的方法)

package com.zbt.day03;

/**
 * Created by luckyboy on 2018/8/15.
 */
public class ThrowExceptionApp {
    public int division(int a,int b){
        int i = 0;
        try{
           i =  a/b;
        }catch (Exception e){
            throw e;
        }
        return i;
    }
}

程式碼測試

package com.zbt.day03;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAdvice {
    @Test
    public void testPerformance(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationConfig.xml");
        ThrowExceptionApp throwExceptionApp = context.getBean("throwExceptionApp",ThrowExceptionApp.class);
        throwExceptionApp.division(1,1);
    }
}