【问题标题】:Logging local variable values with AspectJ使用 AspectJ 记录局部变量值
【发布时间】:2014-07-16 00:55:59
【问题描述】:

我听说过很多关于 AOP 如何帮助模块化日志记录等内容的好消息,但现在当我尝试实现这一点时,我发现 AspectJ 非常有限。

不仅有时不可能将日志记录添加到正确的行,而且访问局部变量值似乎非常困难。您必须确保该变量要么由方法返回,要么用作方法的参数。

日志记录超出被记录代码的范围这一简单事实是一个严重的限制。

是否有更好的方法来访问局部变量值以记录它们?

例如,我有一些维护计数器的代码,我想记录该计数器的值。原始代码如下所示:

int totalMoves = 0;

while(canMove()) {
    // ...
    totalMoves++;
}

Logger.log(totalMoves);

我找不到将这个日志记录代码移动到一个方面的干净 方法。根本无法按原样访问totalMoves。看来我的选择是:

  1. totalMoves 设为可公开访问的字段(反对信息隐藏和封装)
  2. 创建一个只允许 AspectJ 的“挂钩”的虚拟函数(不比直接记录更好)
  3. totalMoves 设为私有字段,但使用反射来访问它(看起来代码味道很糟糕;创建了一个不必要的字段并使对变量的访问变得复杂)

说实话,我猜我在研究 AOP 时所期待的是逐字插入代码以消除横切问题。这些限制让我怀疑 AspectJ 在当前环境中是否值得使用。

这个问题有什么办法吗?还是我以错误的方式接近这个?在这种情况下,我怎样才能干净地记录局部变量?

TL;DR:用 AspectJ 记录局部变量值是一团糟,我怎样才能做得更好?

【问题讨论】:

    标签: logging aspectj aop


    【解决方案1】:

    这个问题已经被问过很多次了。答案是不。 AspectJ 不能拦截对局部变量的读/写操作,只能对成员进行。此外,在某些情况下,JVM 可能会优化掉一些处理局部变量的源代码,但这是另一个话题。

    即使有可能,像这样滥用 AOP 框架也不是一个好主意。它们用于装饰具有附加功能的类或拦截一些可从外部访问的操作,而不是用于破解本地状态。如果某个方面需要知道局部变量名称,这对您的应用程序设计有何影响?

    至于你提到的三个选项,它们并不是你唯一拥有的。您还可以将 totalMoves 设为私有字段,并在有意义的情况下提供 getter 和/或 setter。此外,即使您决定不使用 getter/setter,您仍然可以使用 privileged aspect,它能够与 get|set() pointcuts 结合使用访问私有或受保护字段。

    阅读提供的链接后,如果您不理解此答案,请随时询问。

    【讨论】:

    • 感谢您的回答。对于我正在尝试执行的日志记录类型,方面似乎不是一个好的选择。
    • 您正在尝试做的事情听起来像是调试或不是黑盒(反 OOP)的类和方法。您是否尝试过调试器,甚至是像 Chronon 这样的高级录音工具?我无法想象您想通过在调试模式之外永久添加这种低级日志记录来减慢您的生产代码。无论如何,如果您这样做,请尝试使用 ASM 之类的字节码检测工具。不过,我建议您重构您的应用程序设计。
    • 非常接近调试。这适用于必须进行大量计算的模拟系统。某些类型的计算被记录下来。当出现问题时,通常需要检查很多数字,因此我们将它们打印到日志中。在轻松检测意外值时也很有用。例如,所有代理的平均起始收入应该非常相似。
    【解决方案2】:

    另一种选择是重构你的代码块并从中提取一个方法并添加一个记录其返回值的方面:

    @Log
    private int totalMoves() {
        int totalMoves = 0;
    
        while(canMove()) {
            // ...
            totalMoves++;
        }
    
        return totalMoves;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多