如何基于带注释的参数编写方面切入点
How to write an Aspect pointcut based on an annotated parameter
我在弄清楚如何创建将在具有特定注释参数的 bean 上运行的切入点时遇到了一些麻烦。我的最终目标是在处理参数之前验证参数的值,但目前我只需要创建切入点。
考虑以下注释
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.PARAMETER })
public @interface MyAnnotation {}
然后我想将其应用于多种方法,例如:
public void method1(@MyAnnotation long i) {}
public void method2(String someThing, @MyAnnotation long i) {}
public void method3(String someThing, @MyAnnotation long i, byte value) {}
所以
- 我不关心方法在哪个class(或包)中
- 注释参数的位置会有所不同。
- 我知道带注释的值将仅适用于特定类型
我的切入点实现需要某种东西:
@Before(value = "* *(..) && args(verifyMe)")
public void verifyInvestigationId(long verifyMe) {}
我对 @Before
值到底需要什么以及如何绑定注释及其类型感到有点困惑。在这一点上可能不值得列出我尝试过的东西!
更新:根据我在 中看到的建议(并纠正一些误解并添加 space 我忽略了)我已经到了以下工作的地步:
@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 执行此操作的语法(链接的答案没有显示)。
这是我摆弄它之后的结果(省略导入):
@Aspect
public class VerifyAspect {
@Before("execution(* *(.., @annotations.MyAnnotation (*), ..)) && args(.., verifyMe)")
public void verifyInvestigationId(final Object verifyMe) {
System.out.println("Aspect verifying: " + verifyMe);
}
}
不需要任何 Spring 特定的东西,因为 AspectJ 已经为您提供了需要的参数。
非常类似于 sheltem 已经指出的 my answer here,解决方案看起来像这样(这次是注释式语法,因为在 Spring AOP 中你不能使用本机 AspectJ 语法):
原帖注解:
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 中,class 以及方面需要 Spring beans/components 才能正常工作。
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
我在弄清楚如何创建将在具有特定注释参数的 bean 上运行的切入点时遇到了一些麻烦。我的最终目标是在处理参数之前验证参数的值,但目前我只需要创建切入点。
考虑以下注释
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.PARAMETER })
public @interface MyAnnotation {}
然后我想将其应用于多种方法,例如:
public void method1(@MyAnnotation long i) {}
public void method2(String someThing, @MyAnnotation long i) {}
public void method3(String someThing, @MyAnnotation long i, byte value) {}
所以
- 我不关心方法在哪个class(或包)中
- 注释参数的位置会有所不同。
- 我知道带注释的值将仅适用于特定类型
我的切入点实现需要某种东西:
@Before(value = "* *(..) && args(verifyMe)")
public void verifyInvestigationId(long verifyMe) {}
我对 @Before
值到底需要什么以及如何绑定注释及其类型感到有点困惑。在这一点上可能不值得列出我尝试过的东西!
更新:根据我在 中看到的建议(并纠正一些误解并添加 space 我忽略了)我已经到了以下工作的地步:
@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 执行此操作的语法(链接的答案没有显示)。
这是我摆弄它之后的结果(省略导入):
@Aspect
public class VerifyAspect {
@Before("execution(* *(.., @annotations.MyAnnotation (*), ..)) && args(.., verifyMe)")
public void verifyInvestigationId(final Object verifyMe) {
System.out.println("Aspect verifying: " + verifyMe);
}
}
不需要任何 Spring 特定的东西,因为 AspectJ 已经为您提供了需要的参数。
非常类似于 sheltem 已经指出的 my answer here,解决方案看起来像这样(这次是注释式语法,因为在 Spring AOP 中你不能使用本机 AspectJ 语法):
原帖注解:
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 中,class 以及方面需要 Spring beans/components 才能正常工作。
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