Spring AOP 之三:通知(Advice)方法參數

簡介

前面2篇文章咱們重點介紹的是Spring AOP的流程和Pointcut表達式,咱們處理一些簡單的切面邏輯是沒有問題了,在Pointcut表達式中介紹Pointcut表達式是爲了在什麼地方執行切面邏輯更加靈活,那麼這篇文章介紹的通知參數處理就是爲了讓切面邏輯的作什麼更加靈活。java

JoinPoint

前面2篇介紹的切面邏輯基本上沒有對被代理的邏輯自己作過多的操做,咱們只是在被代理的邏輯(方法,鏈接點,Joinpoint)的先後執行切面邏輯。spring

若是咱們要對被代理的邏輯(方法,鏈接點,Joinpoint)自己進行修改那應該怎麼辦呢?Spring AOP已經爲咱們提供了抽象Joinpoint。其實咱們在前面的Around通知的時候已經簡單的使用到了一點,不過使用的是Joinpoint的子類ProceedingJoinPoint。數組

咱們能夠經過Joinpoint來獲取到代理的邏輯(方法,鏈接點,Joinpoint)的參數,代理對象(proxy),目標對象(target),方法簽名等信息。ide

要使用JointPoint也很容易,會把JoinPoint對象傳入代理方法(Advice方法,如@Before等通知註解的方法)的第一個參數。若是是Around通知出入的是ProceedingJoinPoint。測試

args

除了JoinPoint方式獲取參數以外,還能夠經過在Pointcut表達式中經過args綁定參數,而且還能夠起到限制匹配參數的目的。this

例如:.net

@Before("iAdviceParameter() && args(arg1,arg,..)")
public void joinPointParamterMethodBefore(String arg,Integer arg1){}

上面的表達式就能夠把iAdviceParameter()匹配到的方法(Joinpoint,鏈接點)的參數傳遞到joinPointParamterMethodBefore方法中。注意匹配的方式只和args的順序與類型相關,和joinPointParamterMethodBefore(Advice邏輯(方法))沒有關係。代理

實例

上面的說明對於不是特別瞭解Spring AOP的同窗可能過於抽象,因此下面仍是經過一個實例來講明一下上面介紹的JoinPoint和args的用法。code

下面的例子仍是在原來以前的例子上進行了擴展,固然也能夠單獨的測試。下面仍是先看一下目錄結構。對象

目錄結構

IAdviceParameter

public interface IAdviceParameter {
    
    String JoinPointParamterMethod(Integer arg1 ,String arg2,char arg3);

}

JoinPointParamterMethodImpl

import org.springframework.stereotype.Service;

import cn.freemethod.business.param.IAdviceParameter;

@Service
public class JoinPointParamterMethodImpl implements IAdviceParameter{

    @Override
    public String JoinPointParamterMethod(Integer arg1, String arg2,char arg3) {
        System.out.println(arg1);
        System.out.println(arg2);
        System.out.println(arg3);
        return "result";
    }

}

上面是2個業務邏輯相關的類,以便測試下面切面通知邏輯。

AdviceParameterAspect

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AdviceParameterAspect {
    
    @Pointcut("this(cn.freemethod.business.param.IAdviceParameter)")
    public void iAdviceParameter(){}
    
 //@Before("iAdviceParameter() && args(arg,arg1,..)")
    public void joinPointParamterMethodBefore(String arg1,Integer arg){
        System.out.println("AdviceParameterAspect Advice Before:"+arg1);
        System.out.println("AdviceParameterAspect Advice Before:"+arg);
    }
    
    @After("iAdviceParameter()")
    public void joinPointParamterMethodAfter(JoinPoint jp){
        System.out.println("AdviceParameterAspect Advice After...");
        Object[] args = jp.getArgs();
        for (int i = 0; i < args.length; i++) {
            System.out.println(args[i]);
        }
        System.out.println("kind:"+jp.getKind());
        System.out.println("target:"+jp.getTarget());
        System.out.println("proxy:"+jp.getThis());
        System.out.println("signature:"+jp.getSignature());
        System.out.println("AdviceParameterAspect Advice After...");
    }
    
//    @Around("iAdviceParameter()")
    public void joinPointParamterMethodAround(ProceedingJoinPoint pjp){
        System.out.println("AdviceParameterAspect Advice Around...");
        Object[] args = pjp.getArgs();
        for (int i = 0; i < args.length; i++) {
            System.out.println(args[i]);
        }
        System.out.println("AdviceParameterAspect Advice Around...");
    }
    
//    @Around("iAdviceParameter()")
    public Object joinPointParamterMethodAroundWithResult(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("AdviceParameterAspect Advice Around...");
        Object[] args = pjp.getArgs();
        for (int i = 0; i < args.length; i++) {
            System.out.println(args[i]);
        }
        System.out.println("AdviceParameterAspect Advice Around...");
        return pjp.proceed();
    }

}

上面是一個切面邏輯類,這裏咱們把Pointcut直接寫在了切面之中了。經過上面的例子能夠看到咱們經過JoinPoint獲取到參數數組,獲取目標類(target),獲取代理類(proxy)和方法簽名。

下面咱們重點看一下下面的方法:

@Before("iAdviceParameter() && args(arg,arg1,..)")
    public void joinPointParamterMethodBefore(String arg1,Integer arg){
        System.out.println("AdviceParameterAspect Advice Before:"+arg1);
        System.out.println("AdviceParameterAspect Advice Before:"+arg);
    }

咱們指定在上面的例子中Pointcut會匹配到下面的方法:

public String JoinPointParamterMethod(Integer arg1, String arg2,char arg3)

在Spring執行切面邏輯(方法joinPointParamterMethodBefore)的時候,就會把調用JoinPointParamterMethod的參數和Pointcut中的args列表按位置匹配。和參數的名字無關以後參數的順序有關,當args的參數和joinPointParamterMethodBefore參數匹配的時候就以後參數的名字有關和順序無關。args(arg,arg1,..)中最後的的..表示還有其餘參數。

AspectConfig

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = {"cn.freemethod"})
public class AspectConfig {

}

上面是一個註解配置類。

AdviceParameterStart

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;

import cn.freemethod.business.param.IAdviceParameter;
import cn.freemethod.config.AspectConfig;


public class AdviceParameterStart {
    
    public static void main(String[] args) {
        AbstractApplicationContext  context = new AnnotationConfigApplicationContext(AspectConfig.class);
        IAdviceParameter bean = context.getBean(IAdviceParameter.class);
        String result = bean.JoinPointParamterMethod(1, "ok", 'c');
        System.out.println(result);
        context.close();
    }

}

上面一個是一個啓動類。

注意:爲了輸出的清晰不少都是註釋了,請根據實際要測試的方法取消註釋。

參考

完整工程代碼

Spring AOP 之一:基本概念與流程

Spring AOP 之二:Pointcut註解表達式

相關文章
相關標籤/搜索