使用注释进行跟踪记录
我一直在处理一个公司的代码库,这个公司有一个写大量跟踪日志的策略。因此,几乎每一个方法都有一段代码,启动这样的:使用注释进行跟踪记录
String LOG_METHOD = "nameOfMethod(String,List<Long>):void";
if(logger.isTraceEnabled()) {
Object[] params = new Object[] { string, list };
logger.trace(CompanyMessages.newMethodInstanceMessage(this, LOG_METHOD, params));
}
,并最终像这样(无论是在finally
-clause或只是在方法的末尾:
if(logger.isTraceEnabled()) {
logger.trace(CompanyMessages.leaveMethodInstanceMessage(this, LOG_METHOD));
}
有 这是混乱的代码和其他编码器不断地搞砸他们自己的解释,它不使用特定的CompanyMessages
类,这是需要格式化消息到被监控工具读取,所以我正在寻找一种方法来摆脱全部上面的代码,只是提供所有需要跟踪记录的方法,如注释:@LogBefore('logLevel')
& @LogAfter('logLevel')
。
我选择这个解决方案的原因是让其他开发人员不必学习任何新东西,而是使用注释而不是代码。我正在服务器环境中部署数百个Web应用程序和数十个开发人员。所以我一直在寻找一种在Web应用程序中实现这一功能的方法,而无需额外的编码或额外的大型库。这意味着我正在寻找一个小而稳定的AOP实现,使用类似于我提出的注释的注释,易于在每个Web应用程序中进行配置。性能也很重要。用AOP实现这个最简单的例子是什么?
编辑:我找到something very similar我正在寻找,但这有几个问题。所有需要日志记录的类都必须进行配置,与使用注释相比,这会占用更多的资源。弹簧配置<aop:aspectj-autoproxy/>
会修复吗?
我不认为注解是解决方案。注解一个类或实例意味着在运行时为类提供额外的信息,本身它什么也不做。您需要一些代码来处理具有注释的类,并在运行时基于这些注释的每个方法之前和之后添加代码。
所以没有办法添加注释并准备好去,你的类开始记录他们的方法。
解决方案应该是AOP--这正是问题AOP首先被发明出来的。定义每种方法的类/方法/操作,并解决问题。
好吧,也许你可以把它在运行时与注释和修改类的工作,但你最终自制AOP :-)
貌似面向方面编程(AOP)可以真正帮助您与此有关。它很好地解决了诸如日志和跟踪等交叉问题,它支持所需的注释。
看看AspectJ或Spring AOP。
这将涉及一些AOP原则的学习和您选择的API,但绝对值得您付出努力。尤其是日志和跟踪是您将遇到的第一批AOP教程之一,无需深入就可以轻松完成。
注释和AOP点都是有效的。使用注释来提醒AOP框架关于日志记录。
我会做的另一件事是修复你的记录器。
您有:
String LOG_METHOD = "nameOfMethod(String,List<Long>):void"
if(logger.isTraceEnabled()) {
Object[] params = new Object[] { string, list };
logger.trace(CompanyMessages.newMethodInstanceMessage(this, LOG_METHOD, params));
}
相反,考虑这样的事情:
logger.trace(this, LOG_METHOD, string, list);
,你可以这样实现它:
public void trace(Object obj, Object args...) {
if (parentLogger.isTraceEnabled()) {
logger.trace(CompanyMessages.newMethodInstanceMessage(obj, LOG_METHOD, args);
}
}
大多数日志实用程序被写入在Java中有可变参数之前,所以我们仍然会看到你写的东西。
我们也仍然希望守着防止调用日志时未启用它,但是对于主要动机是因为在过去,大多数人会做你做了什么,或者更糟糕:
logger.trace("My message: " + string + " with list " + list);
无论跟踪是否启用,哪种代价都很高。
但是通过利用可变参数,您可以同时获得两者。只需使用类似的MessageFormat(这你可能做的话),就可以轻松搞定:
logger.trace("My message: {0} with list {1}", string, list);
如果禁用跟踪,这是一种廉价的方法调用传递3个指针。所以保护它并且混淆你的代码的动机就少得多。
大多数现代记录器不能很好地覆盖,所以你通常必须封装它而不是简单地扩展它。
它不直接解决您的问题,动态生成跟踪信息。但这是一个简单的中间立场,可以轻松地逐步清理现有的代码库。
此外,还有2个其他选项。
其中之一就是使用一个后置处理器,它贯穿您的代码并将登录添加到尚不存在的地方。这样可以为您节省打字的负担,而且确实会使代码混乱(因为它仍然存在于任何地方)。
二,在编译时是使用一个注释处理器。这更复杂。但是它在编译期间所做的工作就是在编译时通过这些信息遍历并扩充你的类。好的是你的代码是干净的(除了annotaion之外),但所有的工作都是在编译时完成的。没有运行时影响,而不是Object工厂的花哨类加载器。一旦建成后,您可以将处理器抛弃,这在运行时根本不需要。
有一个项目,谁的名字逃脱我,利用这个。它会在编译时自动将setter/getter添加到您的代码中。我听说过很多好消息。
AOP框架可能会在编译时为你做这件事,我对他们不太熟悉,但无论如何,这种技术值得探索。
尽管如此,包装你的记录器。它是渐进式的,安全的,并且会逐渐清理您的代码,并帮助您记录注释可能无法为您工作的一般情况。
谢谢,这让我意识到我对注释工作的看法是有缺陷的。 – mahler 2011-04-09 12:42:44