【问题标题】:AspectJ pointcut on all methods of a list of classes类列表的所有方法上的 AspectJ 切入点
【发布时间】:2014-06-25 00:01:40
【问题描述】:

我想从一个类列表(可能属于不同的包)中记录所有方法的条目。请注意,方法应仅属于指定的类。

我尝试了以下方法,但这些都不起作用

(1) 使用 if() 切入点 在这里我得到一个错误

"incompatible number of arguments to pointcut, expected 1 found 0"

@Pointcut("execution(*.*(..)) && if()")
public static boolean mycut(JoinPoint jp) {
     boolean matches = ... ;//Test using jp if the declaring class belongs to the list
     return matches;
}

(2) 结合使用Pointcut和aop.xml 在这里我得到一个错误

java.lang.NoSuchMethodError:
com.mypackage.TraceAspect.aspectOf()Lcom/df/jc/aspect/TraceAspect;

//in com.mypackage.TraceAspect aspect class
@Pointcut("execution(*.*(..)) && !within(com.mypackage.TraceAspect)")
public void mycut(){
}

//in aop.xml
<weaver>
    <include within="package1.Class1">
    <include within="package2.Class2">
    <include within="package3.Class3">
</weaver>

这里出了什么问题?

当然可以通过在切入点中单独指定每个类来完成,但这对于数百个类是不可扩展的。理想情况下,如果可以从外部文本文件中获取类列表(以便于配置),那就太好了

【问题讨论】:

  • 找到了这个解决方案,但最好能从aop.xml以外的外部文件中获取所需的类stackoverflow.com/questions/18130336/…
  • 为什么? aop.xml 不够外部吗?顺便说一句,如果你有数百个类,其中许多应该有一些共同点:类名前缀/后缀、包名、实现的接口、标记注释。有几十种方法可以重构代码,以便更容易表达简短的切入点,而不是维护容易出错且通常过时的包含数百个条目的列表。 AOP 并不是要修补糟糕的应用程序设计。恕我直言,您希望这样做的方式是一种症状,而不是问题的根本原因。
  • 这是基于现实世界的要求 - 并非所有代码都是好的代码:1) 源代码中有很多包(我想关注)与其他一些专有的罐子(我不想谈)。 2) 代码是遗留的,写了很多年,有很多用户——所以重构是不可能的 3) 人们可能会争论编写一个预处理器,将类列表转换为 aop.xml,但这会引入两个额外的步骤 - a) 运行预处理器 b) 将 aop.xml 放到正确的类路径中 4) 最后只是寻找一个简单的解决方案
  • 您在自己的代码中使用专有包名称?难以置信。恭喜。无论如何,您根本不需要将这些专有 JAR 暴露给编织者,因此它们完全无关紧要。您想寻求简单的解决方案吗?使用该死的aop.xml! P.S.:重构遗留代码从来都不是不可能的。我的敏捷团队(我是一名 Scrum 教练)每天都使用遗留代码来做这件事。对于任何体面的 IDE,添加标记注释和重新编译应该足够简单。但无论如何:停止在任何解决方案中寻找问题。开始为您的实际问题寻找解决方案。
  • >> 您在自己的代码中使用专有包名称?难以置信。恭喜。 >> 这是我们自己的专有罐子(不是第 3 方)。 >> 但无论如何:不要在任何解决方案中寻找问题。开始为您的实际问题寻找解决方案。来吧!您可以提出解决方案或不提供解决方案,或者根本不发表评论。你能做的最糟糕的事情就是训斥并阻止人们试图找到比你给出的更好的解决方案

标签: aop aspectj pointcut


【解决方案1】:

至于您的最后一条评论:除了糟糕的设计之外,我并没有劝阻您做任何事情,而是试图鼓励您做正确的事情:重构,不要让自己的生活变得比必要的更难。您甚至不了解 AspectJ 语法基础知识,但您已经想要实现一个包含大量类的过于复杂的场景,这是维护的噩梦。我试图通过激励你不要做出短视的决定来提供帮助。相信我,多年来我一直在使用 AspectJ 进行您所谓的具有大量遗留代码的现实项目。避免即使是最便宜的重构也比进行智能重构要昂贵得多——不是太多,但根据童子军规则就足够了:留下比你找到的更干净的营地。有回报的,相信我。

不管怎样,说说你的代码sn-p:

  • execution(*.*(..)) 在语法上是错误的,因为您没有为要匹配的方法指定返回类型(或占位符)。您想使用execution(* *.*(..)) 或简写版本execution(* *(..))
  • 错误“与切入点的参数数量不兼容,预期 1 发现 0”不是来自您的切入点,而是来自您甚至懒得发布的建议。您一定写过类似@Before("mycut()") 的东西,但正确的是@Before("mycut(jp)")

话虽如此,下面是一个简单、完全独立且可编译的示例:

驱动程序应用:

package de.scrum_master.app;

public class Application {
    public static void main(String[] args) {
        System.out.println(multiply(3, add(4, 5)));
    }

    public static int multiply(int i, int j) { return i * j; }
    public static int add(int i, int j) { return i + j; }
}

方面:

package de.scrum_master.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class TraceAspect {
    @Pointcut("execution(* *(..)) && if()")
    public static boolean hasMatchingSignature(JoinPoint thisJoinPoint) {
        return !thisJoinPoint.getSignature().getName().equals("main");
    }

    @Before("hasMatchingSignature(thisJoinPoint)")
    public void myAdvice(JoinPoint thisJoinPoint) {
        System.out.println(thisJoinPoint);
    }
}

示例输出:

execution(int de.scrum_master.app.Application.add(int, int))
execution(int de.scrum_master.app.Application.multiply(int, int))
27

如果您的if() 切入点只返回true,则输出还将显示main 的执行。

【讨论】:

  • +1,尽管我不得不说你的鼓励听起来更像是鞭打。建议(aspectL):下次请想出更好的措辞;-)
  • 谢谢@A4L,我听到了你的声音,没有冒犯。我知道我有时可能有点直率,但实际上 OP 已经找到了如何将他的类列表外部化的解决方案(通过 pom.xml,即所需的外部文件)但并不满足于此,天知道为什么. pom.xml 一个外部文件,甚至是人类可读的文本。添加/删除类名是最简单的。为什么还要进一步外化?好处或额外的间接层在哪里?无论如何,我应该在这里停下来。
  • 感谢您的全面解答
  • 仅供参考,我有 1800 节课。当我使用 aop.xml 方法时,我收到以下错误 java.io.UTFDataFormatException: encoded string too long: 164785 bytes 希望现在我为什么要寻找外部文件机制是有道理的
  • 不,它没有。如果您真的有 1,800 多个课程,那么其中几组肯定有共同点,正如我在您原始帖子下的第一条评论中所说的那样。您可以使用 my.package..*Controller 或类似的小丑来节省大量文本。 AOP 用于横切关注点,其目标通常有一些共同点。我有 99% 的把握,如果我看到你的完整课程列表和你横切的那些,我可以大大缩短你的切入点。列出每个类只会适得其反且难以管理。去重构!不要用工具做傻瓜。我的意思很好。
猜你喜欢
  • 2014-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-12
  • 2015-11-06
  • 1970-01-01
  • 1970-01-01
  • 2020-07-01
相关资源
最近更新 更多