有人可以解释为什么这段代码以这种方式工作吗?我想制作我自己的概念证明 Loggable trait。计划是实例化一个记录器实例,以便继承的类不必做这项工作。但正如我所见,这不是我想要的。
这是代码:
package hu.jonas.simple
trait Loggable {
val logger = java.util.logging.Logger.getLogger(this.getClass.getName)
def whoAmI = {
logger.info(this.getClass.getName)
}
}
class Service extends Loggable {
def answer = {
whoAmI
}
}
object Main extends App {
new Service().answer
}
Run Code Online (Sandbox Code Playgroud)
它产生了以下日志消息:
Jan 25, 2013 2:02:07 PM hu.jonas.simple.Loggable$class whoAmI
INFO: hu.jonas.simple.Service
Run Code Online (Sandbox Code Playgroud)
为什么这两个 this.getClass.getName 不同?此外,当我实例化记录器以获得这个时,我应该写什么:
Jan 25, 2013 2:02:07 PM hu.jonas.simple.Service whoAmI
INFO: hu.jonas.simple.Service
Run Code Online (Sandbox Code Playgroud)
在您的代码中,两次出现都getClass.getName返回相同的值。但是记录器在格式化输出消息时,只是使用源类(它可以通过检查堆栈知道)而不是记录器的名称(在您的情况下对应于getClass.getName)。所以logger在输出日志记录的header时实际上是使用调用的类名log,而日志消息的内容是实例的运行时类名。所以这就像静态与运行时类型问题。如果您想知道Loggable$class来自哪里,那么碰巧的是,名为 的特征中的方法实现T位于名为 的 JVM 类中T$class。
现在举个例子。在下面的代码中,我更改了日志处理程序,以便从源类中删除信息。这会强制记录器使用记录器名称而不是源类名称,并且您会得到预期的行为。
import java.util.logging._
trait Loggable {
val logger = Logger.getLogger(this.getClass.getName)
logger.getParent.getHandlers.foreach{ handler =>
val formatter = handler.getFormatter
handler.setFormatter( new java.util.logging.Formatter {
def format( record: LogRecord ) = {
record.setSourceClassName( null )
formatter.format( record )
}
})
}
def whoAmI = {
logger.info(this.getClass.getName)
}
}
class Service extends Loggable {
def answer = {
whoAmI
}
}
object Main extends App {
new Service().answer
}
Run Code Online (Sandbox Code Playgroud)
现在,为了正确解决您的问题,您可以设置一个名为的属性java.util.logging.SimpleFormatter.format来更改默认日志格式。使用它可以让日志使用记录器名称而不是源类。请参阅http://docs.oracle.com/javase/7/docs/api/index.html?java/util/logging/SimpleFormatter.html。请注意,它需要 Java 7。