有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java 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) 个答案

  1. # 1 楼答案

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

    • 在Java中,类名通常是驼峰大小写,即MyClassSomeAspect而不是myclasssomeAspect
    • Java中的方法名称以小写字符开头,即request而不是Request
    • 您提到了两个注释@Intercept@Interceptor。从现在开始,我假设我们只处理一个叫做@Intercept的问题,好吗
    • 你还用@Intercept注释了aspect的建议,但我猜这不是故意的,是吗?如果拦截建议正在拦截自身,则可能会在另一个切入点中导致无限递归

    至于你的实际问题,那么答案是:某种程度上,但不是静态地在切入点内(因为参数只在运行时确定),而是动态地,也在运行时。你有两个选择:

    选项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()切入点

    ^{} 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