AspectJ - 基于注释函数的切入点建议
AspectJ - pointcut advice based on annotated function
我有 2 个自定义注释:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface FlowPoint {
public enum PointInFlow {
START, END
}
PointInFlow pointInFlow();
}
和:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface ScopeAnnotation {
public enum Category {
BUSINESS, DETECTION, INTERNAL_FUNC, THRESHOLD
}
Category category() default Category.DETECTION;
}
在我的代码中,我用 PointInFlow.START
注释了一个方法,用 Category.DETECTION
和 Category.BUSINESS
注释了其他一些方法
我的切入点是:
@Pointcut("execution(* *(..)) && @annotation(flowPoint) && if()")
public static boolean executeStartMethod(<annotationPackage>.FlowPoint flowPoint) {
return flowPoint.pointInFlow() == FlowPoint.PointInFlow.START;}
@Before("executeStartMethod(flowPoint)")
public void beforeStartMethod(<annotationPackage>.FlowPoint flowPoint, JoinPoint jp) {
logger.infoBefore(jp, flowPoint.pointInFlow());}
@After("executeStartMethod(flowPoint)")
public void afterStartMethod(<annotationPackage>.annotation.FlowPoint flowPoint, JoinPoint jp) {
logger.infoAfter(jp);}
@Pointcut("execution(* *(..)) && @annotation(scopeAnnotation) && if()")
public static boolean executeDetectionMethod(<annotationPackage>.ScopeAnnotation scopeAnnotation) {
return scopeAnnotation.category() == ScopeAnnotation.Category.DETECTION;}
@Before("executeDetectionMethod(scopeAnnotation)")
public void beforeDetectionMethod(<annotationPackage>.ScopeAnnotation scopeAnnotation, JoinPoint jp) {
logger.infoBefore(jp, scopeAnnotation.category());}
@After("executeDetectionMethod(scopeAnnotation)")
public void afterDetectionMethod(<annotationPackage>.ScopeAnnotation scopeAnnotation, JoinPoint jp) {
logger.infoAfter(jp);}
@Pointcut("execution(* *(..)) && @annotation(scopeAnnotation) && if()")
public static boolean executeBusinessMethod(<annotationPackage>.ScopeAnnotation scopeAnnotation) {
return scopeAnnotation.category() == ScopeAnnotation.Category.BUSINESS;}
@Before("executeBusinessMethod(scopeAnnotation)")
public void beforeBusinessMethod(<annotationPackage>.ScopeAnnotation scopeAnnotation, JoinPoint jp) {
logger.infoBefore(jp, scopeAnnotation.category());}
@After("executeBusinessMethod(scopeAnnotation)")
public void afterBusinessMethod(<annotationPackage>.annotation.ScopeAnnotation scopeAnnotation, JoinPoint jp) {
logger.infoAfter(jp);}
问题是 DETECTION 和 BUSINESS 分别在工作,(当我注释掉其中一个检测或业务切入点定义时。)但不像上面那样一起工作。
提前感谢您的帮助
您应该会看到以下 AspectJ 编译错误:
circular advice precedence:
can't determine precedence between two or more pieces of advice that apply to the same join point:
method-execution(void de.scrum_master.app.Application.doEight())
作为解决方法,您可以这样做:
@Pointcut("execution(* *(..)) && @annotation(scopeAnnotation) && if()")
public static boolean executeDetectionOrBusinessMethod(ScopeAnnotation scopeAnnotation) {
return
scopeAnnotation.category() == ScopeAnnotation.Category.DETECTION ||
scopeAnnotation.category() == ScopeAnnotation.Category.BUSINESS;
}
@Before("executeDetectionOrBusinessMethod(scopeAnnotation)")
public void beforeDetectionOrBusinessMethod(ScopeAnnotation scopeAnnotation, JoinPoint jp) {
infoBefore(jp, scopeAnnotation.category());
}
@After("executeDetectionOrBusinessMethod(scopeAnnotation)")
public void afterDetectionOrBusinessMethod(ScopeAnnotation scopeAnnotation, JoinPoint jp) {
infoAfter(jp);
}
或者如果您坚持将两个注释值的切入点和建议分开,只需使用周围建议而不是 before/after:
@Pointcut("execution(* *(..)) && @annotation(scopeAnnotation) && if()")
public static boolean executeDetectionMethod(ScopeAnnotation scopeAnnotation) {
return scopeAnnotation.category() == ScopeAnnotation.Category.DETECTION;
}
@Around("executeDetectionMethod(scopeAnnotation)")
public Object aroundDetectionMethod(ScopeAnnotation scopeAnnotation, ProceedingJoinPoint jp) throws Throwable {
infoBefore(jp, scopeAnnotation.category());
try {
return jp.proceed();
} finally {
infoAfter(jp);
}
}
@Pointcut("execution(* *(..)) && @annotation(scopeAnnotation) && if()")
public static boolean executeBusinessMethod(ScopeAnnotation scopeAnnotation) {
return scopeAnnotation.category() == ScopeAnnotation.Category.BUSINESS;
}
@Around("executeBusinessMethod(scopeAnnotation)")
public Object aroundBusinessMethod(ScopeAnnotation scopeAnnotation, ProceedingJoinPoint jp) throws Throwable {
infoBefore(jp, scopeAnnotation.category());
try {
return jp.proceed();
} finally {
infoAfter(jp);
}
}
不确定如何解决您提出的问题,但无论如何我建议进行重构。
您实际上是在为 3 个不同的注释做同样的事情,所以我会使用调度程序将不同的分支合并为一个分支,并且我可能会按照 @kriegaex 的建议采用 @Around
建议。
我唯一想改变他的答案的是将两个 @Around
建议的相同内容提取到一个通用方法中。
我有 2 个自定义注释:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface FlowPoint {
public enum PointInFlow {
START, END
}
PointInFlow pointInFlow();
}
和:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface ScopeAnnotation {
public enum Category {
BUSINESS, DETECTION, INTERNAL_FUNC, THRESHOLD
}
Category category() default Category.DETECTION;
}
在我的代码中,我用 PointInFlow.START
注释了一个方法,用 Category.DETECTION
和 Category.BUSINESS
我的切入点是:
@Pointcut("execution(* *(..)) && @annotation(flowPoint) && if()")
public static boolean executeStartMethod(<annotationPackage>.FlowPoint flowPoint) {
return flowPoint.pointInFlow() == FlowPoint.PointInFlow.START;}
@Before("executeStartMethod(flowPoint)")
public void beforeStartMethod(<annotationPackage>.FlowPoint flowPoint, JoinPoint jp) {
logger.infoBefore(jp, flowPoint.pointInFlow());}
@After("executeStartMethod(flowPoint)")
public void afterStartMethod(<annotationPackage>.annotation.FlowPoint flowPoint, JoinPoint jp) {
logger.infoAfter(jp);}
@Pointcut("execution(* *(..)) && @annotation(scopeAnnotation) && if()")
public static boolean executeDetectionMethod(<annotationPackage>.ScopeAnnotation scopeAnnotation) {
return scopeAnnotation.category() == ScopeAnnotation.Category.DETECTION;}
@Before("executeDetectionMethod(scopeAnnotation)")
public void beforeDetectionMethod(<annotationPackage>.ScopeAnnotation scopeAnnotation, JoinPoint jp) {
logger.infoBefore(jp, scopeAnnotation.category());}
@After("executeDetectionMethod(scopeAnnotation)")
public void afterDetectionMethod(<annotationPackage>.ScopeAnnotation scopeAnnotation, JoinPoint jp) {
logger.infoAfter(jp);}
@Pointcut("execution(* *(..)) && @annotation(scopeAnnotation) && if()")
public static boolean executeBusinessMethod(<annotationPackage>.ScopeAnnotation scopeAnnotation) {
return scopeAnnotation.category() == ScopeAnnotation.Category.BUSINESS;}
@Before("executeBusinessMethod(scopeAnnotation)")
public void beforeBusinessMethod(<annotationPackage>.ScopeAnnotation scopeAnnotation, JoinPoint jp) {
logger.infoBefore(jp, scopeAnnotation.category());}
@After("executeBusinessMethod(scopeAnnotation)")
public void afterBusinessMethod(<annotationPackage>.annotation.ScopeAnnotation scopeAnnotation, JoinPoint jp) {
logger.infoAfter(jp);}
问题是 DETECTION 和 BUSINESS 分别在工作,(当我注释掉其中一个检测或业务切入点定义时。)但不像上面那样一起工作。
提前感谢您的帮助
您应该会看到以下 AspectJ 编译错误:
circular advice precedence:
can't determine precedence between two or more pieces of advice that apply to the same join point:
method-execution(void de.scrum_master.app.Application.doEight())
作为解决方法,您可以这样做:
@Pointcut("execution(* *(..)) && @annotation(scopeAnnotation) && if()")
public static boolean executeDetectionOrBusinessMethod(ScopeAnnotation scopeAnnotation) {
return
scopeAnnotation.category() == ScopeAnnotation.Category.DETECTION ||
scopeAnnotation.category() == ScopeAnnotation.Category.BUSINESS;
}
@Before("executeDetectionOrBusinessMethod(scopeAnnotation)")
public void beforeDetectionOrBusinessMethod(ScopeAnnotation scopeAnnotation, JoinPoint jp) {
infoBefore(jp, scopeAnnotation.category());
}
@After("executeDetectionOrBusinessMethod(scopeAnnotation)")
public void afterDetectionOrBusinessMethod(ScopeAnnotation scopeAnnotation, JoinPoint jp) {
infoAfter(jp);
}
或者如果您坚持将两个注释值的切入点和建议分开,只需使用周围建议而不是 before/after:
@Pointcut("execution(* *(..)) && @annotation(scopeAnnotation) && if()")
public static boolean executeDetectionMethod(ScopeAnnotation scopeAnnotation) {
return scopeAnnotation.category() == ScopeAnnotation.Category.DETECTION;
}
@Around("executeDetectionMethod(scopeAnnotation)")
public Object aroundDetectionMethod(ScopeAnnotation scopeAnnotation, ProceedingJoinPoint jp) throws Throwable {
infoBefore(jp, scopeAnnotation.category());
try {
return jp.proceed();
} finally {
infoAfter(jp);
}
}
@Pointcut("execution(* *(..)) && @annotation(scopeAnnotation) && if()")
public static boolean executeBusinessMethod(ScopeAnnotation scopeAnnotation) {
return scopeAnnotation.category() == ScopeAnnotation.Category.BUSINESS;
}
@Around("executeBusinessMethod(scopeAnnotation)")
public Object aroundBusinessMethod(ScopeAnnotation scopeAnnotation, ProceedingJoinPoint jp) throws Throwable {
infoBefore(jp, scopeAnnotation.category());
try {
return jp.proceed();
} finally {
infoAfter(jp);
}
}
不确定如何解决您提出的问题,但无论如何我建议进行重构。
您实际上是在为 3 个不同的注释做同样的事情,所以我会使用调度程序将不同的分支合并为一个分支,并且我可能会按照 @kriegaex 的建议采用 @Around
建议。
我唯一想改变他的答案的是将两个 @Around
建议的相同内容提取到一个通用方法中。