当前位置:  开发笔记 > 编程语言 > 正文

Java记录器,自动确定调用者的类名

如何解决《Java记录器,自动确定调用者的类名》经验,为你挑选了5个好方法。

创建堆栈跟踪是一个相对较慢的操作.您的调用者已经知道它所属的类和方法,因此浪费了精力.解决方案的这一方面效率低下.

即使您使用静态类信息,也不应该为每条消息再次获取Logger.来自 Log4j 的作者,CekiGülcü:

包装类中最常见的错误是在每个日志请求上调用Logger.getLogger方法.这可以保证对您的应用程序的性能造成严重破坏.真!!!

这是在类初始化期间获取Logger的传统,高效的习惯用法:

private static final Logger log = Logger.getLogger(MyClass.class);

请注意,这为层次结构中的每种类型提供了单独的Logger.如果您想出一个getClass()在实例上调用的方法,您将看到由基类型记录的消息显示在子类型的记录器下.也许这在某些情况下是可取的,但我发现它令人困惑(而且我倾向于赞成合成而不是继承).

显然,使用动态类型via getClass()将要求您每个实例至少获取一次记录器,而不是像使用静态类型信息的推荐习惯用法那样每个类获取一次.



1> erickson..:

创建堆栈跟踪是一个相对较慢的操作.您的调用者已经知道它所属的类和方法,因此浪费了精力.解决方案的这一方面效率低下.

即使您使用静态类信息,也不应该为每条消息再次获取Logger.来自 Log4j 的作者,CekiGülcü:

包装类中最常见的错误是在每个日志请求上调用Logger.getLogger方法.这可以保证对您的应用程序的性能造成严重破坏.真!!!

这是在类初始化期间获取Logger的传统,高效的习惯用法:

private static final Logger log = Logger.getLogger(MyClass.class);

请注意,这为层次结构中的每种类型提供了单独的Logger.如果您想出一个getClass()在实例上调用的方法,您将看到由基类型记录的消息显示在子类型的记录器下.也许这在某些情况下是可取的,但我发现它令人困惑(而且我倾向于赞成合成而不是继承).

显然,使用动态类型via getClass()将要求您每个实例至少获取一次记录器,而不是像使用静态类型信息的推荐习惯用法那样每个类获取一次.


我认为getLogger方法至少可以在java 6中使用类作为参数.但是你可以使用自Java 5以来的MyClass.class.getCanonicalName().
标准成语是标准的原因.如果你做了不同的事情,请确保必须了解差异的额外维护是值得的.

2> Neeraj..:

该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());


表达式中不需要getSimpleName。私有静态Logger logger = Logger.getLogger(MethodHandles.lookup()。lookupClass());

3> Cowan..:

我们实际上在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);

可能从来没有必要处理那些从其他地方复制并粘贴该行并忘记更改类名的人,让您处理将其所有内容发送到另一个记录器的类.


Matt:如果他们使用不当(就像你说的那样),断言将失败并抛出RuntimeException.这通常会鼓励解决问题.:)(实际上,当我在那家公司时,AFAIK从未发生过这种情况;但在我任职期间至少十几次复制并粘贴记录器并记录错误记录器名称的东西)

4> Daan..:

我想这会为每个课程增加很多开销.每个班级都必须"抬头".你创建新的Throwable对象来做到这一点......这些扔掉的东西不是免费的.


"很多开销"?对于每个类(非对象),此代码将使用此方法执行一次.我认为可以忽略不计.
@Matt:你是对的.但是这种方法通常被声明为静态和最终字段,因为记录器通常是.

5> EGB..:

假设您将静态引用保存到记录器,这里是一个独立的静态单例:

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();


好戏.我建议保留SecurityManager.当您创建它的实例时,它每次都会检查权限.此外,您还必须在doPrivileged()块中实例化LoggerUtils.
推荐阅读
mobiledu2402852357
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有