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注解表达式

相关文章
相关标签/搜索