AspectJ:基于参数值的拦截方法

时间:2015-11-13 09:13:06

标签: java aop aspectj

我使用AspectJ来拦截一个名为Request(String, String)的方法。为此,我使用自己的指定(标记)注释。这就是班级的样子:

Class myclass {
    public void Request(@Intercept String t, String u) {
        // ...
    }
}

拦截@Intercept注释的方面:

@Aspect
class someAspect {
    @Intercept
    @Around("execution(public * * (@Interceptor (*), ..))")
    public void capture(ProceedingJoinPoint pjp) {
        // ...
    }
}

但是,我的方面是根据带注释的参数进行拦截。但我希望方面拦截方法请求对参数t包含的特定值。

例如,如果t == "t1",则必须拦截该方法,否则不会。

我想知道是否可以在AspectJ(与Spring AOP结合使用)中执行此操作。

1 个答案:

答案 0 :(得分:0)

实际上你的代码存在一些问题(我只是重新格式化它,所以它至少是可读的):

  • 在Java类中,名称通常是驼峰式的,即MyClassSomeAspect,而不是myclasssomeAspect
  • Java中的方法名称以小写字母开头,即request而不是Request
  • 您提到了两个注释@Intercept@Interceptor。从现在开始,我将假设实际上我们只处理了一个名为@Intercept,好吗?
  • 您还可以使用@Intercept注释您方面的建议,但我想这不是故意的,是吗?如果拦截建议拦截自己,它可能导致另一个切入点的无限递归......

至于你的实际问题,那么答案是:在切入点中排序(但不是静态)(因为参数仅在runime期间确定),但是在运行时也是动态的。您有两种选择:

选项A:if - 建议代码中的else

package de.scrum_master.app;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Intercept {}
package de.scrum_master.app;

public class Application {
    public static void one(@Intercept String string) {}
    public static void two(String string, String string2) {}
    public static void three(@Intercept String string, int i, int j) {}

    public static void main(String[] args) {
        one("foo");
        two("foo", "bar");
        three("foo", 11, 22);

        one("bingo");
        two("bingo", "bongo");
        three("bingo", 33, 44);
    }
}
package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class InterceptorAspect {
    @Pointcut("execution(public * *(@de.scrum_master.app.Intercept (*), ..)) && args(text, ..)")
    public static void normalPointcut(String text) {}

    @Around("normalPointcut(text)")
    public Object capture(ProceedingJoinPoint thisJoinPoint, String text) {
        if (text != "bingo")
            return thisJoinPoint.proceed();
        System.out.println(thisJoinPoint);
        for (Object arg : thisJoinPoint.getArgs())
            System.out.println("  " + arg);
        // Do something before calling the original method
        Object result = thisJoinPoint.proceed();
        // Do something after calling the original method
        return result;
    }
}

选项B:使用if()切入点

if() pointcut是一个静态方法,它根据您要测试的动态条件返回一个布尔值。重构的方面看起来像这样:

package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class InterceptorAspect {
    @Pointcut("if() && execution(public * *(@de.scrum_master.app.Intercept (*), ..)) && args(text, ..)")
    public static boolean conditionalPointcut(String text) {
        return text != "bingo";
    }

    @Around("conditionalPointcut(text)")
    public Object capture(ProceedingJoinPoint thisJoinPoint, String text) {
        System.out.println(thisJoinPoint);
        for (Object arg : thisJoinPoint.getArgs())
            System.out.println("  " + arg);
        // Do something before calling the original method
        Object result = thisJoinPoint.proceed();
        // Do something after calling the original method
        return result;
    }
}

正如您所看到的,基于参数的动态条件已移至切入点,该切入点不再是具有空体的void方法,而是返回参数检查结果的boolean方法。此外,切入点表达式以if() &&表达式为前缀。

控制台日志:

两个方面变体的控制台输出完全相同:

execution(void de.scrum_master.app.Application.one(String))
  foo
execution(void de.scrum_master.app.Application.three(String, int, int))
  foo
  11
  22