我的应用程序中的大多数方法都是这样编写的:
public void m() {
long t1 = System.currentTimeMillis();
log.info("begin - m()");
/* method body */
long t2 = System.currentTimeMillis();
log.info("end - m(), took " + (t2 - t1) + "ms.");
}
我希望我可以简单地注释我的方法,并自动生成日志语句:
@Log("executionTime")
public void m() {
/* method body */
}
有关如何继续这种方法的任何想法?有没有已知的解决方案?
有人为此建议AOP。问题是,使用AspectJ或Spring AOP,我必须描述所有方法,这些方法与方法本身中的日志调用一样多。
答案 0 :(得分:14)
AspectJ和Spring AOP支持以下内容:
execution(* com.company.project..*.*(..))
将涵盖project
的所有子包中的所有方法。所以不需要逐个定义所有方法。
答案 1 :(得分:3)
正如您所建议的那样,AOP非常适合满足此要求。不确定你的意思是“必须描述所有方法”。据我所知,有一些方法可以使用通配符来指定方面适用的方法,这可以简化你的“描述”工作......至少在Spring AOP的情况下这是真的。不确定其他方面。
是的,Maurice建议的CGLIB是另一个值得您考虑的好候选人。从来没有用过它。
答案 2 :(得分:2)
CGLIB允许您在运行时修改方法代码
答案 3 :(得分:1)
答案 4 :(得分:1)
AspectJ具有连接点的概念,它类似于通配符,可以指定与该通配符匹配的任何方法(您可以在类或任何与通配符匹配的类中指定特定方法) 。然后,您可以创建一个方面,其中包含之前的建议和之后的建议,它们是在连接点匹配的方法之前和之后运行的方法。您可以通过这种方式生成日志方法。
答案 5 :(得分:1)
虽然这对你的问题还不是一个实际的实际答案(对AOP有一些好的答案),但我相信Java 7中ARM的概念应该是实现类似事情的可行选择。这是一个小规模的。
您可以定义一个实用程序日志记录类和一个生成该类的工厂,如下所示:
public class TimerFactory
{
private static final Logger log = ...; // Obtain however
static class Timer implements Disposable<RuntimeException>
{
private final long startTime;
private final String name;
private Timer(String name)
{
this.name = name;
startTime= System.currentTimeMillis();
log.info("begin - " + name);
}
public void close()
{
final long t2 = System.currentTimeMillis();
log.info("end - " + name + ", took " + (t2 - t1) + "ms.");
}
}
public static Timer getTimer(String name)
{
return new Timer(name);
}
}
现在使用该样板(基本上是对日志记录行为的封装),可以按如下方式调用它:
public void m() {
try (TimerFactory.getTimer("m()")) {
/* method body */
}
}
将在try块的入口处调用第一个log方法,并记录开始时间。退出try块时,资源(在这种情况下为Timer
)将自动“关闭”,这将导致计算和记录最终时间。还要注意,因为这是一个try
块,无论是否抛出异常,都会发生结束日志记录。您的原始代码应该使用try-finally块来确保实际完成日志记录。
显然,这仍然需要你在每个站点放置一些日志代码,所以即使Java 7发布,也不能真正取代聪明的切入点和AOP。但是,如果您发现自己不时地将日志记录丢弃到一些方法中,那么这种模式是一种很好的方法来抽象出日志记录问题,并允许您以最少的样板重用它。
答案 6 :(得分:0)
您应该使用此要求的一个方面。这个要求是一个交叉问题(在许多类之间“削减”的担忧)。
要捕获您想要匹配的方法,您应该创建一个与一个或多个连接点匹配的切入点。连接点可以在您的代码上执行(例如,方法)。
查看有关跟踪和记录的this simple examples以及this link about wildcards and pointcuts。
答案 7 :(得分:0)
从@Loggable
(由AspectJ提供支持)尝试jcabi-aspects注释:
@Loggable(Loggable.DEBUG)
public String load(URL url) {
return url.openConnection().getContent();
}
它会记录SLF4J,您可以将其重定向到您自己的日志记录工具,例如log4j。
答案 8 :(得分:-1)
使用唯一搜索字词注释掉日志记录或分析调用:
void myfunc() {
//log-call-123: try { long log_t1 = System.currentTimeMillis();
//log-call-123: log.info("begin - myfunc()"); {
...
normal method code
...
//log-call-123: } } finally { long log_t2 = System.currentTimeMillis();
//log-call-123: log.info("end - myfunc(), took " + (log_t2 - log_t1) + "ms."); }
}
搜索和替换时:
搜索:“//log-call-123:
”
替换为:“/* log-call-123 */
”
如果要关闭额外的日志记录或分析调用,请执行反向搜索和替换。