我正在尝试定义一个方面来注入记录器。
我希望创建类似的东西:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public aspect LogInjector {
private pointcut executionJoinPoints(): !within(LogInjector) && execution (* *.*(..));
before(): executionJoinPoints(){
// Get class name of the executed code
clazz = ...
final Logger logger = LogManager.getLogger(clazz);
// Get method name of the executed code
method = ...
// Get params name, type and values triplet or values at least if the previous is not possible, of the executed code
params = ...
// Get call stack of the executed code
stack = ...
logger.trace("{}.{}({}) - {}", clazz.name(), method.name(), params, stack);
}
after(): executionJoinPoints(){
// Get class name of the executed code
clazz = ...
final Logger logger = LogManager.getLogger(clazz);
// Get method name of the executed code
method = ...
// Get return value or exception of the executed code
result = ...
logger.trace("{}.{} = {}", clazz.name(), method.name(), result);
}
}
为此,我想检索执行元数据/上下文数据:
- 异常
- 返回值
如何获取此元数据/上下文数据?
为了保持方面的效率,我建议如下:
- 将切入点限制为您真正希望调试的目标包和类。不要记录/追踪整个世界。您还可以使用带有抽象切入点的抽象基本方面,并将该方面扩展为带有具体切入点的具体子方面。如果使用加载时编织,后者甚至可以通过XML配置提供
- 使用
around()
建议,而不是before()
/after()
对。然后,您只需要计算一些记录的值一次,并在通过proceed()
进行原始方法调用之前和之后使用它们 - 只需记录
thisJoinPoint
,而不是默认情况下将其中包含的位拼接在一起。这已经为您提供了连接点的类型、方法签名,包括参数类型和返回值 - 不要记录参数名称,这些信息不会增加任何实际值。此外,参数名称需要进行重构,并且只有在使用调试信息编译代码时才会出现。保持简单,只记录参数值
- 在上面提到的
around()
建议中,您可以将proceed()
调用封装到try-catch-finally
中,方便地处理和记录任何异常以及堆栈跟踪和/或将检查的异常封装到AspectJ的SoftException
或简单的RuntimeException
中,然后重新抛出它们。适用于您情况的任何内容 - 方法调用结果只是
proceed()
的结果,这也是您需要从around()
建议中返回的结果。您也可以返回其他内容(但它必须具有正确的返回类型(,或者如果出于任何原因希望跳过目标方法执行,则完全跳过proceed()
我刚才说的所有内容都写在AspectJ手册或任何其他AspectJ教程中。在问这样一个一般性问题之前,你可能想下次读一些。