我有一个带有数据库调用的类,我通常希望使用log4j记录此类中带有(带参数)的每个方法:
logger.debug("foo(id="+id+") initiated");
是否可以自动执行此操作?也许在每个方法的开头使用某种注释而不是编写每一个logger.debug?
今天每次更改参数或方法名称时,我都必须更新我的logging.debug。
答案 0 :(得分:8)
如果您有声明要记录调用的方法的接口,则可以使用标准Proxy API来实现您想要的效果。
Proxy API允许您将实际实现包装在一个新的代理类中,该类将记录调用,并将调用转发给实现。您只需要实现一个InvocationHandler
来执行日志记录和转发。
例如,
interface Calculator {
int add(int a, int b);
}
class CalculatorImpl implements Calculator {
@Override public int add(int a, int b) { return a+b; }
}
class LoggingInvocationHandler implements InvocationHandler {
private final Object delegate;
public LoggingInvocationHandler(final Object delegate) {
this.delegate = delegate;
}
@Override invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method: " + method + ", args: " + args);
return method.invoke(delegate, args);
}
}
class X {
public static void main(String... args) {
final Calculator calc = new CalculatorImpl();
final Calculator loggingCalc =
(Calculator) Proxy.newProxyInstance(X.class.getClassLoader(),
new Class[] {Calculator.class},
new LoggingInvocationHandler (calc));
loggingCalc.add(2, 3); // shall print to the screen
}
}
您还可以通过更改InvocationHandler
中的代码轻松记录方法引发的返回值和异常。此外,您可以使用您喜欢的任何日志记录框架,而不是示例中的System.out.println
。
要记录返回值和异常,您可以执行以下操作:
@Override invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method: " + method + ", args: " + args);
try {
final Object ret = method.invoke(delegate, args);
System.out.println("return: " + ret);
return ret;
} catch (Throwable t) {
System.out.println("thrown: " + t);
throw t;
}
}
答案 1 :(得分:7)
从@Loggable
尝试jcabi-aspects注释和AspectJ方面(我是开发人员):
@Loggable(Loggable.INFO)
public String load(URL url) {
return url.openConnection().getContent();
}
所有方法调用都通过SLF4J记录。
答案 2 :(得分:5)
一种可能的解决方案是使用aspectj。想法是将方面附加到您希望记录的每个方法,并且执行日志记录是方面而不是方法。 aspectj日志记录的一个示例是right here in stackoverflow。