利用Spring AOP的通知類型以及建立通知

寫在最前端

  • 1.SpringAOP中共有六種通知類型,只要咱們自定義一個類實現對應的接口,它們全都是org.springframework.aop包中的。
  • 2.AOP的鏈接點能夠是方法調用、方法調用自己、類初始化、對象實例化時,可是SpringAOP中全是方法調用,更簡單,也最實用
通知名稱 接口
前置通知 org.springframework.aop.MethodBeforeAdvice
後置返回通知 org.springframework.aop.AfterReturningAdvice
後置通知 org.springframework.aop.AfterAdvice
環繞通知 org.springframework.aop.MethodInterceptor
異常通知 org.springframework.aop.ThrowsAdvice
引入通知 org.springframework.aop.IntroductionInterceptor

寫一個公共類,用於目標對象前端

public class Person {
    private String name;
    public boolean saySomething(String something){
        System.out.println("Pereson類中說了一句:"+something);
return true;//默認返回true
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

1、建立前置通知(也就是目標方法調用前執行)

  • 前置通知能夠修改傳遞給方法的參數,而且能夠經過拋出異常來阻止方法的執行,能夠用前置通知實現用戶登陸的驗證,SpringSecurity就是這麼作的java

    1.例子:在一個方法執行前將包含方法名稱的消息寫入到控制檯中,而且將傳入的參數修改下。(文章中寫的內容比較小,大多數在代碼中有註釋,你們能夠下載代碼查看)

/**
 * 前置通知類
 */
public class BeforeAdvice implements MethodBeforeAdvice {


    @Override
    public void before(Method method, Object[] objects, @Nullable Object o) throws Throwable {
          //第一個參數是目標方法對象,第二個是參數,第三個是作爲調用目標的object(這是personr實例)
        //打印方法名
        System.out.println("要執行的方法是:"+method.getName());
        //修改參數爲lyn4ever
        objects[0]="lyn4ever";//咱們修改爲爲了lyn4ever,因此打印出來的就是lyn4ever,而不是zhangsan
    }


    public static void main(String[] args) {
        Person person = new Person();

        ProxyFactory pf  =new ProxyFactory();
        pf.addAdvice(new BeforeAdvice());
        pf.setTarget(person);

        Person proxy = (Person) pf.getProxy();

        //我這裏傳的參數是zhangsan,理論上它應該打印出來zhangsan
        proxy.saySomething("zhangsan");

    }

}

title

沒毛病,原本我輸入的是zhangsan,在aop中將參數改成了lyn4ever,這樣就完美的替換了。git

2、後置返回通知

是在鏈接點(方法調用)返回後執行,這顯然不能像上邊那樣修改參數,也不能修改返回值。可是能夠拋出能夠發送到堆棧的異常,一樣也能夠調用其餘方法。github

/**
 * 後置返回通知
 */
public class AfterReturnAdvice implements AfterReturningAdvice {

    @Override
    public void afterReturning(@Nullable Object o, Method method, Object[] objects, @Nullable Object o1) throws Throwable {
        /*
        參數和前置通知是同樣的
        這個是在返回以後調用,所以,person中的saySomething會先打印,咱們在這裏修改的參數不起做任何做用
         */

        System.out.println("調用的方法是:"+method.getName()+"這句是在saySomething以後");//這句是在saySomething以後
        objects[0]="lyn4ever";//這句能夠修參數,可是以前的方法已經執行過了,因此不起任何做用

        System.out.println("咱們修改了參數爲:"+objects[0]+"可是沒有任何用");//這時候這個參數並不會傳到person.saysomething(),由於已經調用過了

    }


    public static void main(String[] args) {
        Person person = new Person();

        ProxyFactory pf = new ProxyFactory();
        pf.addAdvice(new AfterReturnAdvice());//注意修改這個爲當前類中的通知類
        pf.setTarget(person);

        Person proxy = (Person) pf.getProxy();
        proxy.saySomething("zhangsan");
    }
}

title

3、環繞通知

這人最好理解了,就是在方法調用先後均可以執行代碼。看起來像是前置後後置的集合,可是它能夠修改方法的返回值,由於它實現的invoke方法的返回值是Object,因此咱們就能夠修改,而前置通知的返回是void,因此無法修改的。甚至以致於咱們能夠不調用目標對象中的鏈接點方法,咱們徹底修改這個方法的所有代碼。spring

public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        return null;
    }
}

雖然這個invoke()方法中並無提供像以前的那些參數,可是這一個invocation實例能夠獲得
title
title
代碼示例ide

/**
 * 環繞通知
 */
public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        
        //在這個invoation中有一切咱們想要的方法相關
        System.out.println("類名是:"+invocation.getThis().getClass().getName());
        System.out.println("目標方法是:"+invocation.getMethod().getName());

        Object[] arguments = invocation.getArguments();//這個就是參數
        System.out.println("第一個參數 是:"+arguments[0]);

        //咱們修改第一個參數爲lyn4ever
        arguments[0]="lyn4ever";


        invocation.proceed();//執行目標方法


        System.out.println("這個是在以後執行的");

        return false;//修改返回值
    }


    public static void main(String[] args) {
        Person person = new Person();

        ProxyFactory pf = new ProxyFactory();
        pf.addAdvice(new MyMethodInterceptor());//注意修改這個爲當前類中的通知類
        pf.setTarget(person);

        Person proxy = (Person) pf.getProxy();
        boolean flag = proxy.saySomething("zhangsan");
        System.out.println(flag);//方法原本是要返回true的
    }
}

能夠看到,咱們修改了目標方法返回的值。ui

本文demo已提交至githubthis

相關文章
相關標籤/搜索