13

クラスを使用する特殊なロガークラスがありますjava.util.logging.Logger。このロガーを別のクラスのシャットダウン フックで使用できるようにしたいと考えています。ただし、シャットダウン時にログに記録されないようです。私が読んだことから、問題を引き起こしているロガー自体に対してアクティブ化されたシャットダウンフックが既に存在する可能性があります。

どうすればこれを機能させることができますか? 理想的には、プロセスが終了したときに実際にシャットダウン フックを実行したことがログ ファイルに表示されるようにしたいと考えています。

4

2 に答える 2

18

再度ソースを見ると、Logger がシャットダウン時に動作し続けるようにメソッドjava.util.logging.managerをオーバーライドする LogManager のサブクラスであるシステム プロパティを定義することが解決策のようです。reset();

import java.util.logging.LogManager;
import java.util.logging.Logger;

public class Main {
    static {
        // must be called before any Logger method is used.
        System.setProperty("java.util.logging.manager", MyLogManager.class.getName());
    }

    public static class MyLogManager extends LogManager {
        static MyLogManager instance;
        public MyLogManager() { instance = this; }
        @Override public void reset() { /* don't reset yet. */ }
        private void reset0() { super.reset(); }
        public static void resetFinally() { instance.reset0(); }
    }

    public static void main(String... args) {
        Logger logger1 = Logger.getLogger("Main1");
        logger1.info("Before shutdown");
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Logger logger2 = Logger.getLogger("Main2");
                    logger2.info("Shutting down 2");

                } finally {
                    MyLogManager.resetFinally();
                }
            }
        }));
    }
}

版画

Dec 11, 2012 5:56:55 PM Main main
INFO: Before shutdown
Dec 11, 2012 5:56:55 PM Main$1 run
INFO: Shutting down 2

LogManager のこのコードから、ハンドラーを分解して閉じるシャットダウン フックがあることがわかります。ロガーは、以前に使用されていない場合にのみシャットダウン時に機能するため、このコードは実行されません。

// This private class is used as a shutdown hook.
// It does a "reset" to close all open handlers.
private class Cleaner extends Thread {

    private Cleaner() {
        /* Set context class loader to null in order to avoid
         * keeping a strong reference to an application classloader.
         */
        this.setContextClassLoader(null);
    }

    public void run() {
        // This is to ensure the LogManager.<clinit> is completed
        // before synchronized block. Otherwise deadlocks are possible.
        LogManager mgr = manager;

        // If the global handlers haven't been initialized yet, we
        // don't want to initialize them just so we can close them!
        synchronized (LogManager.this) {
            // Note that death is imminent.
            deathImminent = true;
            initializedGlobalHandlers = true;
        }

        // Do a reset to close all active handlers.
        reset();
    }
}


/**
 * Protected constructor.  This is protected so that container applications
 * (such as J2EE containers) can subclass the object.  It is non-public as
 * it is intended that there only be one LogManager object, whose value is
 * retrieved by calling Logmanager.getLogManager.
 */
protected LogManager() {
    // Add a shutdown hook to close the global handlers.
    try {
        Runtime.getRuntime().addShutdownHook(new Cleaner());
    } catch (IllegalStateException e) {
        // If the VM is already shutting down,
        // We do not need to register shutdownHook.
    }
}

私自身のテストから

Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            Logger logger2 = Logger.getLogger("Main2");
            logger2.info("Shutting down 2");
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }
}));

版画

Dec 11, 2012 5:40:15 PM Main$1 run
INFO: Shutting down 2

しかし、追加すると

Logger logger1 = Logger.getLogger("Main1");

このブロックの外では何も得られません。

于 2012-12-11T17:41:57.267 に答える
0

シャットダウンフックには利点がありますか?

main の最後の行にログ出力を追加することをお勧めします。VM がクラッシュした場合を除き、すべての場合に finally ブロックが実行されますが、シャットダウン フックも実行されません。

static void main(String[] argv) {

  try {
    startApp();
  } finally {
    LOGGER.info("shudown");
  }
}
于 2012-12-11T17:35:38.027 に答える