AspectJ-基于注释功能的切入点建议

时间:2018-08-22 14:32:07

标签: annotations aop aspectj aspect pointcut

我有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.DETECTIONCategory.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);}

问题是“检测”和“业务”分别工作((当我注释掉检测或业务切入点定义之一时)。)但并非如上所述。

提前感谢您的帮助

2 个答案:

答案 0 :(得分:1)

您应该看到以下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);
}

或者,如果您坚持将两个注释值的切入点和建议分开,只需在周围使用建议而不是之前/之后:

@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);
  }
}

答案 1 :(得分:0)

不确定如何解决您提出的问题,但是无论如何我还是建议进行重构。

您实际上对3个不同的注释执行了相同的操作,因此我将把不同的分支与一个调度程序合并为一个分支,并且可能会使用@Around的建议,如@kriegaex所建议的。

我唯一想改变他的答案的方法是将两个@Around通知的相同正文提取到一个通用方法。