如何正确使用Spring AOP选择使用特定注释注释的方法的执行?

时间:2015-04-15 14:56:57

标签: java spring spring-mvc aop spring-aop

我正在学习Spring AOP ,我对我的学习资料中发现的排名有以下疑问。

请考虑以下切入点:执行(@ com.myapp.MyCustomAnnotation void *(..))。究竟意味着什么?

它给了我以下答案,在我看来是一个愚蠢的奇怪(使用我对AOP如何工作的知识)。它说:

  

这将选择代表voiud方法的联合点   由 @ com.myapp.MyCustomAnnotation 注释注释。

好的,这意味着使用 AOP 我可以指定何时执行使用特定注释注释的特定方法?是对的还是我错过了什么?

因此,如果先前的断言是正确的,则意味着(例如)我还可以指定类似的内容:"当执行由 @RequestMapping注释的控制器方法时(" / listAccounts&#34)? (这意味着,当控制器处理HttpRequest朝向 / listAccounts 资源执行类似的操作时:

execution(@RequestMapping("/listAccounts") * *(..))

我可以这样做吗?

3 个答案:

答案 0 :(得分:1)

Spring正在使用AspectJ切入点表达式语言(https://eclipse.org/aspectj/doc/next/adk15notebook/annotations-pointcuts-and-advice.html

应用你的切入点表达式意味着拦截所有带有'void'返回类型的名称和参数列表的方法调用,只要该方法使用@ com.myapp.MyCustomAnnotation进行注释即可。

虽然使用Annotation-Parameters无法匹配Join-Points,所以你的第二个Pointcut-Expression无效。

答案 1 :(得分:1)

您无法在切入点中明确指定注释的参数。相反,您可以设置切入点以使用@RequestMapping注释捕获所有方法,然后从方法中检索注释并检查该值是否与端点匹配。例如:

@PointCut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
public void requestMapping() {}

@Before("requestMapping()")
public void handleRequestMapping(JoinPoint joinPoint) {
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    Method method = signature.getMethod();
    String mapping = method.getAnnotation(RequestMapping.class).value()[0];

    if (mapping.equals("/listAccounts") {
        // do something
    }
}

答案 2 :(得分:0)

AndréR。的答案是不正确的,因为 可以限制与参数值的注释匹配,但是有一个限制:它只适用于简单类型,如字符串,整数和类,而不是字符串数组左右。但在您的具体示例中,Spring注释@RequestMapping的值类型为String[],请参阅Javadoc。让我们假设你有这种情况:

<强>注释:

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;

@Target(value={ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    int value();
    String name() default "";
    Class<?> type() default Object.class;
}

驱动程序应用程序:

这里我们有一个应用程序,其中有几个方法由Spring注释@RequestMapping和我们自制的注释@MyAnnotation注释:

package de.scrum_master.app;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

public class Application {
    @RequestMapping("/listAccounts")
    @MyAnnotation(11)
    public void doSomething() {}

    public void doSomethingElse() {}

    @RequestMapping(value = {"/listAccounts","/another/method"}, name = "Newton")
    @MyAnnotation(value = 22, type = String.class)
    public void foo() {}

    @RequestMapping(value = "/listAccounts", method = RequestMethod.POST, name = "Einstein")
    @MyAnnotation(value = 11, name = "John Doe", type = String.class)
    public void bar() {}

    @RequestMapping(value = "/listCustomers", method = RequestMethod.GET, name = "Einstein")
    @MyAnnotation(value = 22, name = "Jane Doe")
    public void zot() {}

    @RequestMapping(value = "/listAccounts", produces = {"application/json","application/xml"}, consumes = "text/html", name = "Newton")
    public void baz() {}

    public static void main(String[] args) {
        Application application = new Application();
        application.doSomething();
        application.doSomethingElse();
        application.foo();
        application.bar();
        application.zot();
        application.baz();
    }
}

注释匹配方面:

package de.scrum_master.aspect;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.web.bind.annotation.RequestMapping;

import de.scrum_master.app.MyAnnotation;

@Aspect
public class AnnotationParameterMatcher {
    // Match *all* methods annotated by @RequestMapping
    @Before("execution(* *(..)) && @annotation(requestMapping)")
    public void logRequestMapping(JoinPoint thisJoinPoint, RequestMapping requestMapping) {
        // Print joinpoint and annotation
        System.out.println(thisJoinPoint + " -> " + requestMapping);
    }

    // Match *all* methods annotated by @RequestMapping
    @Before("execution(* *(..)) && @annotation(requestMapping)")
    public void logMatchingValue(JoinPoint thisJoinPoint, RequestMapping requestMapping) {
        // Only print if value array contains "/listAccounts"
        if (Arrays.asList(requestMapping.value()).contains("/listAccounts"))
            System.out.println("  value contains '/listAccounts'");
    }

    // Match *all* methods annotated by @RequestMapping and bind 'name' parameter
    @Before("execution(* *(..)) && @annotation(RequestMapping(name))")
    public void logName(JoinPoint thisJoinPoint, String name) {
        System.out.println("  name = '" + name + "'");
    }

    // Match methods annotated by @MyAnnotation with value=11
    @Before("execution(@MyAnnotation(value=11) * *(..))")
    public void logName(JoinPoint thisJoinPoint) {
        System.out.println("  @MyAnnotation(value=11) detected");
    }

    // Match methods annotated by @MyAnnotation with 3 specific parameter values 
    @Before("execution(@MyAnnotation(value=11, name=\"John Doe\", type=String.class) * *(..)) && @annotation(myAnnotation)")
    public void logName(JoinPoint thisJoinPoint, MyAnnotation myAnnotation) {
        System.out.println("  " + myAnnotation);
    }
}

控制台输出:

execution(void de.scrum_master.app.Application.doSomething()) -> @org.springframework.web.bind.annotation.RequestMapping(headers=[], method=[], name=, produces=[], params=[], value=[/listAccounts], consumes=[])
  value contains '/listAccounts'
  name = ''
  @MyAnnotation(value=11) detected
execution(void de.scrum_master.app.Application.foo()) -> @org.springframework.web.bind.annotation.RequestMapping(headers=[], method=[], name=Newton, produces=[], params=[], value=[/listAccounts, /another/method], consumes=[])
  value contains '/listAccounts'
  name = 'Newton'
execution(void de.scrum_master.app.Application.bar()) -> @org.springframework.web.bind.annotation.RequestMapping(headers=[], method=[POST], name=Einstein, produces=[], params=[], value=[/listAccounts], consumes=[])
  value contains '/listAccounts'
  name = 'Einstein'
  @MyAnnotation(value=11) detected
  @de.scrum_master.app.MyAnnotation(name=John Doe, type=class java.lang.String, value=11)
execution(void de.scrum_master.app.Application.zot()) -> @org.springframework.web.bind.annotation.RequestMapping(headers=[], method=[GET], name=Einstein, produces=[], params=[], value=[/listCustomers], consumes=[])
  name = 'Einstein'
execution(void de.scrum_master.app.Application.baz()) -> @org.springframework.web.bind.annotation.RequestMapping(headers=[], method=[], name=Newton, produces=[application/json, application/xml], params=[], value=[/listAccounts], consumes=[text/html])
  value contains '/listAccounts'
  name = 'Newton'