美文网首页
04 AOP学习之通知参数

04 AOP学习之通知参数

作者: 幽暗金 | 来源:发表于2018-01-13 09:52 被阅读0次

    Spring AOP通知参数

    前边章节已经介绍了声明通知,但如果想获取被被通知方法参数并传递给通知方法,该如何实现呢?接下来我们将介绍两种获取通知参数的方式。

    1. 使用JoinPoint获取

    Spring AOP提供使用org.aspectj.lang.JoinPoint类型获取连接点数据,任何通知方法的第一个参数都可以是JoinPoint(环绕通知是ProceedingJoinPoint,JoinPoint子类),当然第一个参数位置也可以是JoinPoint.StaticPart类型,这个只返回连接点的静态部分。

    1. JoinPoint:提供访问当前被通知方法的目标对象、代理对象、方法参数等数据:

      public interface JoinPoint {
      
          String toString();                  //连接点所在位置的相关信息  
          String toShortString();             //连接点所在位置的简短相关信息  
          String toLongString();              //连接点所在位置的全部相关信息
          Object getThis();                   //返回AOP代理对象,如果想要使用这个方法的话,最好使用this连接点,这样可以获得最佳的性能。  
          Object getTarget();                 //返回目标对象,如果想要使用这个方法的话,最好使用target连接点,这样可以获得最佳的性能。
          Object[] getArgs();                 //返回被通知方法参数列表  
          Signature getSignature();           //返回当前连接点签名  
          SourceLocation getSourceLocation(); //返回连接点方法所在类文件中的位置  
          String getKind();                   //连接点类型  
          StaticPart getStaticPart();         //返回连接点静态部分  
      
          // getKind 方法的返回值
          static String METHOD_EXECUTION = "method-execution";
          static String METHOD_CALL = "method-call";
          static String CONSTRUCTOR_EXECUTION = "constructor-execution";
          static String CONSTRUCTOR_CALL = "constructor-call";
          static String FIELD_GET = "field-get";
          static String FIELD_SET = "field-set";
          static String STATICINITIALIZATION = "staticinitialization";
          static String PREINITIALIZATION = "preinitialization";
          static String INITIALIZATION = "initialization";
          static String EXCEPTION_HANDLER = "exception-handler";
          static String SYNCHRONIZATION_LOCK = "lock";
          static String SYNCHRONIZATION_UNLOCK = "unlock";
          static String ADVICE_EXECUTION = "adviceexecution"; 
      }
      
    2. ProceedingJoinPoint:用于环绕通知,使用proceed()方法来执行目标方法:

    public interface ProceedingJoinPoint extends JoinPoint {  
        void set$AroundClosure(AroundClosure arc);              // 这是个内部方法,不应该直接调用
        public Object proceed() throws Throwable;               // 执行目标函数,以默认的参数执行
        public Object proceed(Object[] args) throws Throwable;  // 执行目标函数,并传入所需的参数
    }  
    
    1. JoinPoint.StaticPart:提供访问连接点的静态部分,如被通知方法签名、连接点类型等:
    public interface StaticPart {
        Signature getSignature();           // 返回当前连接点签名
        SourceLocation getSourceLocation(); // 返回连接点所在资源路径
        String getKind();                   // 连接点类型
        int getId();                        // 唯一标识 
        String toString();                  // 连接点所在位置的相关信息
        String toShortString();             // 连接点所在位置的简短相关信息
        String toLongString();              // 连接点所在位置的全部相关信息
    }
    

    如果使用该种方式声明参数,必须放到方法第一个位置上,如

    @Aspect
    @Component
    public class JoinPointAop {
    
        // 切点范围
        @Pointcut("execution(* com.learn.service..IJoinPointService+.*(..))")
        public void pointcut(){ }
    
        @Before("pointcut()")
        public void before1(JoinPoint jp) {
            System.out.println("---------------@Before1----------------");
            System.out.println(Arrays.toString(jp.getArgs()));
        }
    
        @Before("pointcut()")
        public void before2(JoinPoint.StaticPart jp) {
            System.out.println("---------------@Before2----------------");
            System.out.println(jp.getSignature());
        }
    
        @Around("pointcut()")
        public Object around(ProceedingJoinPoint pjp) throws Throwable {
            System.out.println("---------------@Around----------------");
            return pjp.proceed();
        }
    
    }
    

    2. 手动指定

    通过切入点表达式可以将相应的参数自动传递给通知方法。

    在Spring AOP中,除了execution和bean指示符不能传递参数给通知方法,其他指示符都可以将匹配的相应参数或对象自动传递给通知方法。

    简单使用

    例:

    @Before(value="execution(* com.learn.service..IAppointService+.say(*)) && args(param)", argNames="param") //明确指定了
    public void before1(String param) {
        System.out.println("===param:" + param);
    }
    

    切入点表达式execution( com.learn.service..IAppointService+.say()) && args(param)**:

    1. 首先execution(* com.learn.service..IAppointService+.say(*))匹配IAppointService接口的实现类的say方法,且有一个任何类型的参数;
    2. args(param)将首先查找通知方法上同名的参数,并在方法执行时(运行时)匹配传入的参数是使用该同名参数类型,即java.lang.String;如果匹配将把该被通知参数传递给通知方法上同名参数。
      其中argNames可以省略不写,但是省略的话如果在class文件中没生成变量调试信息是获取不到方法参数名字的
    3. 如果想使用JoinPoint当做参数的话,也需要在argNames中指定,如:
      @Before(value="execution(* com.learn.service..IAppointService+.say(*)) && args(param)", argNames="jp, param") //明确指定了
      public void before1(JoinPoint jp, String param) {
          System.out.println("===JoinPoint:" + jp.getKind());
          System.out.println("===param:" + param);
      }
      

    组合使用

    @Before(value = "pointcut() && args(param) && this(service) && @annotation(secure)", argNames = " jp, param, service, secure")
    public void before2(JoinPoint jp, String param, IAppointService service, Secure secure) {
        service.logInfo("==before==");
        System.out.println("===JoinPoint:" + jp.getKind());
        System.out.println("===param:" + param);
        System.out.println("===secure:" + secure.value());
    }
    

    也可以使用引用切入点的方式获取参数:

    @Pointcut(value = "args(param)", argNames = "param")
    private void pointcut1(String param) {
    }
    
    @Pointcut(value = "@annotation(secure)", argNames = "secure")
    private void pointcut2(Secure secure) {
    }
    @Before(value = "pointcut1(param) && pointcut2(secure)", argNames = "jp, param, secure")
    public void before3(JoinPoint jp, String param, Secure secure) {
        System.out.println("before3");
    }
    

    相关文章

      网友评论

          本文标题:04 AOP学习之通知参数

          本文链接:https://www.haomeiwen.com/subject/hdxfoxtx.html