如何根据带注释的参数编写 Aspect 切入点 [英] How to write an Aspect pointcut based on an annotated parameter

查看:28
本文介绍了如何根据带注释的参数编写 Aspect 切入点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在弄清楚如何创建一个切入点时遇到了一些麻烦,该切入点将对具有特定注释参数的 bean 进行操作.我的最终目标是在处理之前验证参数的值,但目前我只需要创建切入点.

I'm having a bit of trouble working out how to create a pointcut that will operate on beans that have a specific annotated parameter. My eventual aim is to validate the value of the parameter before it's processed, but for the moment I just need to create the pointcut.

考虑以下注释

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.PARAMETER })
public @interface MyAnnotation {}

然后我想将其应用于多种方法,例如:

I'd then like to apply this to a number of methods like:

public void method1(@MyAnnotation long i) {}
public void method2(String someThing, @MyAnnotation long i) {}
public void method3(String someThing, @MyAnnotation long i, byte value) {}

所以

  • 我不在乎方法在哪个类(或包)中
  • 带注释的参数的位置会有所不同.
  • 我知道带注释的值仅适用于特定类型

我的切入点实现需要某些:

@Before(value = "* *(..) && args(verifyMe)")
public void verifyInvestigationId(long verifyMe) {}

我对 @Before 值到底需要是什么以及如何绑定注释及其类型感到有些困惑.在这一点上,可能不值得列出我尝试过的东西!

I'm getting a bit confused about exactly what that @Before value needs to be and how to tie in the annotation and its type. At this point it's probably not worth listing the things I've tried!

更新:根据我在 http://stackoverflow.com/questions/3565718/pointcut-matching-methods-with-annotated-parameters/3567170#3567170(和纠正一些误解并增加我忽略的空间)我已经到了以下工作的地步:

Update: Based on the advice I've seen in http://stackoverflow.com/questions/3565718/pointcut-matching-methods-with-annotated-parameters/3567170#3567170 (and correcting a couple of misunderstandings and adding space I overlooked) I've got to the point where the following works:

@Before("execution(public * *(.., @full.path.to.MyAnnotation (*), ..))")
public void beforeMethod(JoinPoint joinPoint) {
    System.out.println("At least one of the parameters are annotated with @MyAnnotation");
}

这几乎就是我需要的——我需要做的就是将带注释的参数的值作为参数传递给方法.我不太清楚让 Spring 执行此操作的语法(链接的答案未显示这一点).

This is almost what I need - all I need to do is pass the value of the annotated argument as an parameter to the method. I can't quite work out the syntax to get Spring to do this (the linked answer does not show this).

推荐答案

非常类似于 我在这里的回答sheltem 已经指出,解决方案是这样的(这次是注解风格的语法,因为在 Spring AOP 中你不能使用原生的 AspectJ 语法):

Very similar to my answer here which sheltem already pointed to, the solution looks like this (in annotation-style syntax this time because in Spring AOP you cannot use native AspectJ syntax):

原海报注释:

package annotations;

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

驱动程序应用:

我使用驱动程序应用程序来测试我的 AspectJ 解决方案.在 Spring 中,类和方面都需要是 Spring bean/组件才能使其工作.

I use the driver application in order to test my AspectJ solution. In Spring the class as well as the aspect need to be Spring beans/components in order for this to work.

package de.scrum_master.app;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import annotations.MyAnnotation;

public class Application {
    public void method1(@MyAnnotation int i) {}
    public void method2(String id, @MyAnnotation float f) {}
    public void method3(int i, @MyAnnotation List<String> strings, @MyAnnotation String s) {}
    public void method4(int i, @MyAnnotation Set<Integer> numbers, float f, boolean b) {}
    public void method5(boolean b, String s, @MyAnnotation String s2, float f, int i) {}
    public void notIntercepted(boolean b, String s, String s2, float f, int i) {}

    public static void main(String[] args) {
        List<String> strings = new ArrayList<String>();
        strings.add("foo");
        strings.add("bar");
        Set<Integer> numbers = new HashSet<Integer>();
        numbers.add(11);
        numbers.add(22);
        numbers.add(33);

        Application app = new Application();
        app.method1(1);
        app.method2("foo", 1f);
        app.method3(1, strings, "foo");
        app.method4(1, numbers, 1f, true);
        app.method5(false, "foo", "bar", 1f, 1);
        app.notIntercepted(false, "foo", "bar", 1f, 1);
    }
}

方面:

package de.scrum_master.aspect;

import java.lang.annotation.Annotation;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.SoftException;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;

import annotations.MyAnnotation;

@Aspect
public class ArgCatcherAspect {
    @Before("execution(public * *(.., @MyAnnotation (*), ..))")
    public void interceptMethodsWithAnnotatedParameters(JoinPoint thisJoinPoint) {
        System.out.println(thisJoinPoint);
        MethodSignature signature = (MethodSignature) thisJoinPoint.getSignature();
        String methodName = signature.getMethod().getName();
        Class<?>[] parameterTypes = signature.getMethod().getParameterTypes();
        Annotation[][] annotations;
        try {
            annotations = thisJoinPoint.getTarget().getClass().
                getMethod(methodName, parameterTypes).getParameterAnnotations();
        } catch (Exception e) {
            throw new SoftException(e);
        }
        int i = 0;
        for (Object arg : thisJoinPoint.getArgs()) {
            for (Annotation annotation : annotations[i]) {
                if (annotation.annotationType() == MyAnnotation.class) {
                    System.out.println("  " + annotation + " -> " + arg);
                    // Verify 'arg' here or do whatever
                }
            }
            i++;
        }
    }
}

控制台日志:

execution(void de.scrum_master.app.Application.method1(int))
  @annotations.MyAnnotation() -> 1
execution(void de.scrum_master.app.Application.method2(String, float))
  @annotations.MyAnnotation() -> 1.0
execution(void de.scrum_master.app.Application.method3(int, List, String))
  @annotations.MyAnnotation() -> [foo, bar]
  @annotations.MyAnnotation() -> foo
execution(void de.scrum_master.app.Application.method4(int, Set, float, boolean))
  @annotations.MyAnnotation() -> [33, 22, 11]
execution(void de.scrum_master.app.Application.method5(boolean, String, String, float, int))
  @annotations.MyAnnotation() -> bar

这篇关于如何根据带注释的参数编写 Aspect 切入点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆