Java子类中的日志记录器

9
为了让C.run()使用自己的类记录器,我是否应该在B中添加一个public/protected方法getLogger()呢?
public abstract class A extends Thread {
    @Override
    public abstract void run();
}

public class B extends A {

    private static final Logger logger = Logger.getLogger(B.class.getName());

    @Override
    protected void run() {
        // do something

        logger.info("B");
    }
}

public class C extends B {
}

你得到了什么输出?你试过了吗? - Vincent Mimoun-Prat
为什么需要子类来使用自己的日志记录器? - Dmitry Stropalov
A类的每个子类都将由任务引擎执行。一些类(例如我的示例中的C)扩展了另一个任务。如果C没有覆盖B.run(),我就无法强制它使用自己的记录器。除非我添加一个getLogger()方法。 - Nicklas
但是如果C没有覆盖B.run(),那么C在做什么呢?假设它有被调用的方法,你可以将这些方法记录到它自己的日志记录器中。如果你真的想要(并且确定这是一个好主意),始终记录到B、C Logger实例中,具体取决于哪个是具体实现,你可以拥有getLogger()方法,该方法以多态方式返回层次结构中最低的Logger。 - planetjones
2个回答

14

最好将记录器(Logger)设置在类级别(Class level)。因此,如果C需要自己的Logger,则在C中声明自己的Logger,例如:

private static final Logger logger = Logger.getLogger(C.class.getName());

这样,当C运行一些代码时,它会记录到自己的Logger中,当B运行时,它也会记录到自己的Logger中。这样你就能清楚地看到哪个类记录了什么。

如果这不是您想要的,请扩展问题并说明您想要实现什么以及为什么。

我不确定以下代码是否是一个好主意(我总是希望物理运行代码的类是记录器),但它应该可以工作:

public abstract class A extends Thread {
    @Override
    public abstract void run();
    protected abstract Logger getLogger();
}

public class B extends A {

    private static final Logger logger = Logger.getLogger(B.class.getName());

    @Override
    public void run() {
        getLogger().info("B");
    }

    @Override
    protected Logger getLogger() {return logger;);  
}

public class C extends B {

    private static final Logger logger = Logger.getLogger(C.class.getName());

    @Override
    protected Logger getLogger() {return logger;);  
}

你修改我的示例恰好就是我看到的一个可能的解决方案。 - Nicklas
如果这是你想要的,那没问题 - 这是我能想到的唯一方法(现在已经恢复了 - 我错过了花括号... 哎呀!) - planetjones
如果您可以接受记录器不是静态的话,@StKiller提供的另一个答案可以实现与此回答相同的效果,但代码更为简洁。 - cellepo

5
您可以在基类中使用此方法:
protected Logger logger = Logger.getLogger(this.getClass().getName());

this.getClass() 会使用子类名称初始化日志记录器。


3
我猜把它改成非静态的问题在于每个 Object 的实例都会调用这个方法。我知道它会返回已经存在的 logger,但是每次创建新的实例时仍然需要在 java.util.Logger 类中执行额外的代码来查找它。 - planetjones
1
是的,但我没有看到任何没有缺陷的解决方案。无论如何,如果每个新子类都需要按指定样式定义一个新的记录器 - 在我的看法中,这是一个设计问题。 - StKiller
1
我会删除"If you will use non-abstract base class",因为你可以在抽象基类中使用它。此外,使用this是不必要的,因为你可以直接使用getClass() - Jason S
跟进@Jason_S的评论,使这个答案中的代码更加简洁... '.getName()'也可以被移除:仅使用Class<?>构造将返回一个相同的记录器;该构造函数本身在其中调用getName()。 - cellepo
2
这个不起作用。当你调用logger.info("whatever")时,格式化程序将打印声明“logger”的类名,而不是从“this.getClass().getName()”返回的类名,即使“logger.getName()”返回正确的值。 - DanielCuadra
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接