【问题标题】:AspectJ - pointcut advice based on annotated functionAspectJ - 基于注释函数的切入点建议
【发布时间】:2018-08-22 14:32:07
【问题描述】:

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

问题是 DETECTION 和 BUSINESS 分别工作,(当我注释掉其中一个检测或业务切入点定义时。)但不是像上面那样一起工作。

提前感谢您的帮助

【问题讨论】:

    标签: annotations aop aspectj aspect pointcut


    【解决方案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);
      }
    }
    

    【讨论】:

    • 感谢您的评论 我使用了这些方法,但出现以下错误,并不太清楚是什么问题,我尝试在 google 上搜索,发现它可能与某些依赖项问题有关或不匹配的版本号,但我检查了 min 并没有发现任何不匹配:原因:Java 异常:java.lang.reflect.InvocationTargetException 引起:java.lang.NoClassDefFoundError:org/aspectj/runtime/internal/AroundClosure
    • 您在我们的聊天中告诉我,您在我不太了解的 OSGi 设置中使用 LTW,例如你如何触发编织。无论如何,您需要将 aspectjweaver.jar 放在类路径中,以便 AspectJ 找到运行时类并能够检测您的代码。但是这个问题超出了您在这里的原始问题的范围,我已经给出了正确的答案。因此,如果您同意,请接受答案。
    • 对 - 谢谢亚历克斯,你是一个真正的 aspectJ 专业指南 :) !!! 1 为您服务
    • 我要感谢@kriegaex 的帮助 - 方面工作正常,原因是:Java 异常:java.lang.reflect.InvocationTargetException 原因:java.lang.NoClassDefFoundError: org/aspectj/ runtime/internal/AroundClosure 是因为Equinox jars 使用其他OSGI 包进行初始化。你让我学到了很多方面的知识——再次感谢!!!
    【解决方案2】:

    不确定如何解决您所说的问题,但我还是建议重构。

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

    我对他的回答唯一要改变的是将两个@Around 建议的相同主体提取到一个通用方法中。

    【讨论】:

    • 我使用了这些方法,我得到了以下错误,并不太清楚是什么问题,我尝试在谷歌上搜索,我发现它可能与某些依赖项问题或版本号不匹配有关,但我检查了 min 并没有发现任何不匹配:原因:Java 异常:java.lang.reflect.InvocationTargetException 引起:java.lang.NoClassDefFoundError:org/aspectj/runtime/internal/AroundClosure
    • @ShicoRen 在我看来你的类路径上有一个不兼容的 aspectjrt.jar 版本
    • 感谢@Sean Patrick Floyd 的问题原因:Java 异常:java.lang.reflect.InvocationTargetException 原因:java.lang.NoClassDefFoundError: org/aspectj/runtime/internal/AroundClosure 是因为春分jars 使用其他 OSGI 包进行初始化。你让我学到了很多方面的知识——再次感谢!!!
    • @ShicoRen 总是乐于提供帮助 :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    • 2011-09-29
    • 1970-01-01
    • 2013-02-12
    • 2013-02-12
    • 1970-01-01
    相关资源
    最近更新 更多