In diesem Mkyong-Tutorial wird vorgeschlagen, Logger folgendermaßen zu initialisieren:
@Controller
public class WelcomeController {
private static final Logger logger = Logger.getLogger(WelcomeController.class);
// etc
}
Vermutlich initialisiert vermutlich jede andere Klasse, die einen Logger hat, ihre Logger auf die gleiche Weise.
Meine Frage ist - ist das der beste Weg, es zu tun? Es scheint ... sich zu wiederholen.
getLogger()
den Namen des Loggers angeben, der abgerufen werden soll.Antworten:
Ihr Kommentar besagt, dass "ausführlich" sich auf die Notwendigkeit bezieht, diese Codezeile in jeder Klasse zu wiederholen. Meine erste Antwort ist, dass das Hinzufügen von zwei Codezeilen (Variablendefinition plus Importanweisung) zu jeder Klasse im Großen und Ganzen keine so große Sache ist. Zumal Sie sie nur zu den Klassen hinzufügen müssen, die Verhalten haben und daher die Protokollierung durchführen müssen. Die von Ihnen verwendete Codezeile ist jedoch anfällig für Fehler beim Kopieren und Einfügen (dazu später mehr).
Da Sie jedoch Alternativen wünschen, sind hier einige aufgeführt, mit Gründen, aus denen Sie diese möglicherweise verwenden möchten oder nicht.
Verwenden Sie einen einzelnen Logger für die gesamte App
Wenn Sie sich nicht darum kümmern, welche Klasse Bericht erstattet, oder bereit sind, den gesamten erforderlichen Kontext in die Nachricht einzufügen, erledigt ein einfacher Singleton-Logger die Aufgabe:
Meiner Meinung nach besteht einer der großen Vorteile eines Protokollierungsframeworks darin, dass der Kontext von separaten Protokollierungsinstanzen bereitgestellt wird - schon allein, um die Protokollnachrichten an verschiedene Ziele zu leiten. Ich würde das nicht aufgeben, nur um eine Codezeile zu speichern (Sie benötigen noch den Import).
Außerdem erhöht dies die Ausführlichkeit am Verwendungsort, was zu weitaus mehr Tastenanschlägen führt.
Erstellen Sie Ihre Logger am Verwendungsort
Ich werfe dieses raus, nur weil es die Variable eliminiert. Ich glaube nicht, dass ich das kommentieren muss. Obwohl es meine bevorzugte Technik zum Abrufen einer Logger-Instanz zeigt.
Verwenden Sie einen Bean-Postprozessor, um den Logger zu injizieren
In Ihrem Beispiel wird Spring verwendet, und mit Spring können Sie sich in den Bean-Initialisierungscode einbinden. Sie können einen Postprozessor erstellen, der die Bean auf eine
logger
Mitgliedsvariable überprüft und eineLogger
Instanz erstellt, wenn sie eine findet.Während ein solcher Postprozessor nur aus ein paar Dutzend Codezeilen besteht, ist er ein weiterer bewegender Teil Ihrer Anwendung und daher eine weitere potenzielle Fehlerquelle. Ich bevorzuge es, so wenig wie möglich davon zu haben.
Verwenden Sie ein Mixin
Scala und Groovy bieten Eigenschaften , mit denen Sie das Verhalten zusammenfassen können. Ein typisches Scala-Muster besteht darin, ein
Logging
Merkmal zu erstellen und es dann der Klasse hinzuzufügen, die protokolliert werden muss:Dies bedeutet leider, dass Sie die Sprache wechseln müssen. Sofern Sie nicht Java 8 verwenden, können Sie in diesem Fall eine
Logging
Schnittstelle mit einer "Standardmethode" erstellen :Jetzt können Sie innerhalb Ihres Klassencodes einfach verwenden
Dies ist zwar einfach, hat jedoch einige Nachteile. Zum einen verschmutzt es die Schnittstelle jeder Klasse, die es verwendet, da alle Schnittstellenmethoden öffentlich sind. Vielleicht nicht so schlimm, wenn Sie es nur für Klassen verwenden, die von Spring instanziiert und injiziert werden, insbesondere wenn Sie die Trennung von Schnittstelle und Implementierung befolgen.
Das größere Problem ist, dass bei jedem Aufruf die tatsächliche Logger-Instanz nachgeschlagen werden muss. Welches ist schnell, aber unnötig.
Und Sie benötigen noch eine Importanweisung.
Verschieben Sie den Logger in eine Oberklasse
Ich wiederhole: Ich finde wiederholte Logger-Definitionen nicht ausführlich, aber wenn Sie dies tun, halte ich dies für den besten Ansatz, um sie zu beseitigen.
Jetzt erben Ihre Controller-Klassen von
AbstractController
und haben Zugriff auf dielogger
Variable. Denken Sie daran, dass Sie die@Controller
Anmerkung in die konkrete Klasse einfügen müssen.Einige Leute werden dies als eine Perversion der Vererbung empfinden. Ich habe versucht, sie zu beruhigen, indem ich die Klasse benannte
AbstractController
und nichtAbstractProjectClass
. Sie können selbst entscheiden, ob es eine Beziehung gibt oder nicht .Andere Personen lehnen die Verwendung einer Instanzvariablen anstelle einer statischen Variablen ab. Statische IMO- Protokollierer sind anfällig für Fehler beim Kopieren und Einfügen, da Sie explizit auf den Klassennamen verweisen müssen.
getClass()
stellt sicher, dass Ihr Logger immer korrekt ist.quelle
MethodHandles.lookup().lookupClass()
die besser ist alsObject.getClass()
?MethodHandles.lookup().lookupClass()
kann für statische Variablen verwendet werden, ist nicht anfällig für Fehler beim Kopieren und Einfügen und ist schnell: stackoverflow.com/a/47112323/898747 Es bedeutet zwar einen zusätzlichen Inport, aber ich mag es sehr, wenn meine Logger statisch sind, also ist es zumindest einen Wert wert Erwähnung :)Um die von @kdgregory bereitgestellte Antwort zu erweitern, stellt Groovy
@Slf4j
(groovy.util.logging.Slf4j
) sofort als Annotation bereit , die eine AST-Transformation für die Klasse ausführt, um sie mit einem Logger zu versehen, derlog
standardmäßig den Variablennamen annimmt, wenn er nicht angegeben wird.quelle