创建堆栈跟踪是一个相对较慢的操作.您的调用者已经知道它所属的类和方法,因此浪费了精力.解决方案的这一方面效率低下.
即使您使用静态类信息,也不应该为每条消息再次获取Logger.来自 Log4j 的作者,CekiGülcü:
包装类中最常见的错误是在每个日志请求上调用Logger.getLogger方法.这可以保证对您的应用程序的性能造成严重破坏.真!!!
这是在类初始化期间获取Logger的传统,高效的习惯用法:
private static final Logger log = Logger.getLogger(MyClass.class);
请注意,这为层次结构中的每种类型提供了单独的Logger.如果您想出一个getClass()
在实例上调用的方法,您将看到由基类型记录的消息显示在子类型的记录器下.也许这在某些情况下是可取的,但我发现它令人困惑(而且我倾向于赞成合成而不是继承).
显然,使用动态类型via getClass()
将要求您每个实例至少获取一次记录器,而不是像使用静态类型信息的推荐习惯用法那样每个类获取一次.
创建堆栈跟踪是一个相对较慢的操作.您的调用者已经知道它所属的类和方法,因此浪费了精力.解决方案的这一方面效率低下.
即使您使用静态类信息,也不应该为每条消息再次获取Logger.来自 Log4j 的作者,CekiGülcü:
包装类中最常见的错误是在每个日志请求上调用Logger.getLogger方法.这可以保证对您的应用程序的性能造成严重破坏.真!!!
这是在类初始化期间获取Logger的传统,高效的习惯用法:
private static final Logger log = Logger.getLogger(MyClass.class);
请注意,这为层次结构中的每种类型提供了单独的Logger.如果您想出一个getClass()
在实例上调用的方法,您将看到由基类型记录的消息显示在子类型的记录器下.也许这在某些情况下是可取的,但我发现它令人困惑(而且我倾向于赞成合成而不是继承).
显然,使用动态类型via getClass()
将要求您每个实例至少获取一次记录器,而不是像使用静态类型信息的推荐习惯用法那样每个类获取一次.
该MethodHandles类(如Java 7)包括查找类,从静态上下文,可以找到并返回当前类的名称.请考虑以下示例:
import java.lang.invoke.MethodHandles; public class Main { private static final Class clazz = MethodHandles.lookup().lookupClass(); private static final String CLASSNAME = clazz.getSimpleName(); public static void main( String args[] ) { System.out.println( CLASSNAME ); } }
运行时会产生:
Main
对于记录器,您可以使用:
private static Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
我们实际上在LogUtils类中有类似的东西.是的,它有点狡猾,但就我而言,优点是值得的.我们希望确保我们没有任何开销,因为它被重复调用,所以我们(有点hackily)确保它只能从静态初始化器上下文调用,la:
private static final Logger LOG = LogUtils.loggerForThisClass();
如果从普通方法或实例初始化程序调用它(即如果"静态"不在上面),它将失败,以降低性能开销的风险.方法是:
public static Logger loggerForThisClass() { // We use the third stack element; second is this method, first is .getStackTrace() StackTraceElement myCaller = Thread.currentThread().getStackTrace()[2]; Assert.equal("", myCaller.getMethodName()); return Logger.getLogger(myCaller.getClassName()); }
有人问过这有什么好处
= Logger.getLogger(MyClass.class);
可能从来没有必要处理那些从其他地方复制并粘贴该行并忘记更改类名的人,让您处理将其所有内容发送到另一个记录器的类.
我想这会为每个课程增加很多开销.每个班级都必须"抬头".你创建新的Throwable对象来做到这一点......这些扔掉的东西不是免费的.
假设您将静态引用保存到记录器,这里是一个独立的静态单例:
public class LoggerUtils extends SecurityManager { public static Logger getLogger() { String className = new LoggerUtils().getClassName(); Logger logger = Logger.getLogger(className); return logger; } private String getClassName() { return getClassContext()[2].getName(); } }
用法很干净:
Logger logger = LoggerUtils.getLogger();