この質問は、私は今日早く答えskiphoppy's questionに関連しています。
デフォルトの初期化は、クラスローディング時に一度だけ実行されるハードコードされたスタティックブロックであるため、AOP(アスペクト比)が必要です。これは、指向プログラミング)、より具体的には、静的初期化子を傍受するためのAspectJ。私はskiphoppyの他の質問にmy answerでそれを行う方法を説明しました。
これで、静的な初期化を傍受してLogManagerをトリックしてURLを伝えることができますが、コードブロック全体を再実行するには、ワーカーオブジェクトパターンという別のトリックが必要です。ここではサンプルコードがあり、説明は次のとおりです。
サンプル・アプリケーションクラス:
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
public class Log4jDemo {
public static Runnable log4jDefaultInitCmd;
private static Logger logger = Logger.getLogger("scrum-master.de");
public static void main(String[] args) throws InterruptedException {
BasicConfigurator.configure();
logger.info("Hello world!");
logger.info("Now sleeping for 2 sec...");
Thread.sleep(2000);
logger.info("I am awake again!");
if (log4jDefaultInitCmd != null) {
logger.info("Re-running log4j default initialisation");
log4jDefaultInitCmd.run();
}
logger.info("Done");
}
}
アスペクト傍受静的初期化LogManager
の:
import org.apache.log4j.LogManager;
public aspect Log4jAspect {
Object around() : staticinitialization(LogManager) {
System.out.println("log4j static initialisation");
Log4jDemo.log4jDefaultInitCmd = new Runnable() {
@Override public void run() {
proceed();
}
};
Log4jDemo.log4jDefaultInitCmd.run();
return null;
}
}
がどのように動作します:
AOPの一般的な概念を説明するのはこの答えの範囲を超えているので、理解しているか、それを理解するために何かを読むつもりであると思います。
Log4jAspect
インターセプトLogManager
のaround()
アドバイスは静的初期化。
- アドバイス内では、
proceed()
コール(つまり、静的初期化の実行)は、匿名Runnable
インスタンスによって実装されたワーカーオブジェクト内にパッケージ化されています。これは効果的に呼び出すことができるrun()
メソッドを持つオブジェクトに呼び出しを効果的にラップします。
- 静的な初期化をラップした後、
Runnable
インスタンスを別のクラスのパブリック静的メンバーに割り当てて、アスペクトの外部からアクセスできるようにします(例:Scalaのような動的言語では、これを字句スコープと呼びます)。 。
- アドバイスの中で、ワーカーオブジェクトの
run()
メソッドを呼び出すことによって静的な初期化を進めます。
これまでのところ、LogManager
クラスがロードされていて、アスペクトが存在しないかのように正しく初期化されました。しかし今ではLog4jDemo.main
を見てください:
- 私たちはロガーを初期化し、いくつかのイベントを記録します。
- 2秒間待っています(これまでに起こったことについてコンソール出力を確認するのに十分な時間です)。
- 我々は続行し、は、ワーカーオブジェクトの
run()
メソッドをもう一度呼び出すことによって、デフォルトの初期化を再発行します。 log4j static initialisation
log4j: Trying to find [log4j.xml] using context classloader [email protected]
log4j: Trying to find [log4j.xml] using [email protected] class loader.
log4j: Trying to find [log4j.xml] using ClassLoader.getSystemResource().
log4j: Trying to find [log4j.properties] using context classloader [email protected]
log4j: Using URL [file:/C:/Dokumente%20und%20Einstellungen/Robin/Eigene%20Dateien/java-src/dummy2/bin/log4j.properties] for automatic log4j configuration.
log4j: Reading configuration from URL file:/C:/Dokumente%20und%20Einstellungen/Robin/Eigene%20Dateien/java-src/dummy2/bin/log4j.properties
log4j: Parsing for [root] with value=[debug, stdout].
log4j: Level token is [debug].
log4j: Category root set to DEBUG
log4j: Parsing appender named "stdout".
log4j: Parsing layout options for "stdout".
log4j: Setting property [conversionPattern] to [%d{ABSOLUTE} %5p %c{1}:%L - %m%n].
log4j: End of parsing for "stdout".
log4j: Setting property [target] to [System.out].
log4j: Parsed "stdout" options.
log4j: Finished configuring.
12:41:22,647 INFO de:13 - Hello world!
0 [main] INFO scrum-master.de - Hello world!
12:41:22,663 INFO de:14 - Now sleeping for 2 sec...
16 [main] INFO scrum-master.de - Now sleeping for 2 sec...
12:41:24,663 INFO de:16 - I am awake again!
2016 [main] INFO scrum-master.de - I am awake again!
12:41:24,663 INFO de:18 - Re-running log4j default initialisation
2016 [main] INFO scrum-master.de - Re-running log4j default initialisation
log4j: Trying to find [log4j.xml] using context classloader [email protected]
log4j: Trying to find [log4j.xml] using [email protected] class loader.
log4j: Trying to find [log4j.xml] using ClassLoader.getSystemResource().
log4j: Trying to find [log4j.properties] using context classloader [email protected]
log4j: Using URL [file:/C:/Dokumente%20und%20Einstellungen/Robin/Eigene%20Dateien/java-src/dummy2/bin/log4j.properties] for automatic log4j configuration.
log4j: Reading configuration from URL file:/C:/Dokumente%20und%20Einstellungen/Robin/Eigene%20Dateien/java-src/dummy2/bin/log4j.properties
log4j: Parsing for [root] with value=[debug, stdout].
log4j: Level token is [debug].
log4j: Category root set to DEBUG
log4j: Parsing appender named "stdout".
log4j: Parsing layout options for "stdout".
log4j: Setting property [conversionPattern] to [%d{ABSOLUTE} %5p %c{1}:%L - %m%n].
log4j: End of parsing for "stdout".
log4j: Setting property [target] to [System.out].
log4j: Parsed "stdout" options.
log4j: Finished configuring.
12:41:24,663 INFO de:21 - Done
2016 [main] INFO scrum-master.de - Done
Tadaa:あなたは、コマンドライン引数-Dlog4j.debug=true
を使用している場合
は
、次のように表示されます!ご覧のとおり、デフォルトの初期化は実際に2回実行されています。ログの出力はそれを証明します。たとえば、ログにUsing URL [file:/(...)]
が2回表示されます。
結論:
これは特に良い方法はありませんが、それはハードコードされたが、APIの呼び出しを介してユーザーに公開されていないことが、より望ましい状況と比較に再発行のlog4jのデフォルトの初期化、事実はそのままで、このトリックが必要です。どのような状況でも、デフォルトの完全初期化ブロックを再実行する必要があるのは間違いありませんが、その質問には尋ねられたので、回避策を提案するのではなく、正確に答えたいと思いました。楽しい!
私はconfigureandwatchがあなたのニーズに合っていないと思います(http://logging.apache.org/log4j/1.2/faq.html#a3.6) – fglez
"configureandwatch"は役に立ちません。変わらない。とにかくおかげさまで、ありがとう! – curd0