Wenn Sie Logback als Abmeldungskomponente in Ihrer Anwendung verwenden, konfigurieren die meisten von ihnen die Datei "logback.xml". Darüber hinaus können Sie in der Produktionsumgebung die Protokollebene in der Datei logback.xml direkt ändern und wirksam werden, ohne die Anwendung neu zu starten. Wie ist diese Funktion implementiert?
Wenn Sie Logback als Abmeldungskomponente in Ihrer Anwendung verwenden, konfigurieren die meisten von ihnen die Datei logback.xml. Darüber hinaus können Sie in der Produktionsumgebung die Protokollebene in der Datei logback.xml direkt ändern und wirksam werden, ohne die Anwendung neu zu starten.
Wie ist diese Funktion implementiert?
I. Problembeschreibung und Analyse
Werfen Sie als Reaktion auf das obige Problem zuerst einen tatsächlichen Fall. In meiner persönlichen Website Z+werden alle Geräte dynamisch hinzugefügt und über Konfigurationsdateien versteckt. Da es nur einen Server gibt, werden die Konfigurationsdateien vereinfacht und direkt in einem Verzeichnis auf dem Server platziert.
Wenn ich nun ein Problem habe, muss ich die Änderung erkennen, wenn sich der Inhalt dieser Datei ändert
Eine der einfachsten Möglichkeiten, an die man sich vorstellen kann, ist die Umfrage, um festzustellen, ob die Datei geändert wurde. Wenn es geändert wird, wird es neu geladen und aktualisiert. Daher sind die Hauptprobleme, über die besorgt sein müssen, wie folgt:
Ii. Design und Implementierung
Nachdem das Problem abstrahiert wurde, ist die entsprechende Lösung klarer
Dann ist eine sehr einfache Implementierung einfacher:
public class FilePest {privat letztes letztes Mal; @Test public void testFileUpdate () {Datei Datei = new File ("/tmp/alarmconfig"); // Zunächst der zuletzt modifizierte Zeitstempel der Datei lastTime = Datei.lastModified (); // zeitgesteuerte Aufgabe bestimmt, ob die Datei jede Sekunde geändert hat, dh bestimmt, ob LastModified ändert plantexecutorService afuledexecutorService = Executors.NewScheduledThreadpool (1); enderEdexecutorService.ScheduleatFixedRate (new Runnable () {@Override public void run () {if (file.lastModified ()> lastTime) {system.out.println ("Dateiaktualisierung! Zeit:" + Datei.LastModified (); TimeUnit.seconds); try {thread.sleep (1000 * 60); } catch (interruptedException e) {e.printstacktrace (); }}}Das obige ist eine sehr einfache und sehr grundlegende Implementierung, die unsere Bedürfnisse im Grunde entsprechen kann. Was ist das Problem mit dieser Implementierung?
Was passiert, wenn eine Ausnahme während der Ausführung einer Zeitaufgabe auftritt?
Nehmen Sie einige Änderungen am obigen Code vor
public class FilePest {privat letztes letztes Mal; private void tt () {neue nullpointerexception (); } @Test public void testFileUpdate () {Datei Datei = new File ("/tmp/alarmconfig"); lastTime = file.lastModified (); TeplanedexecutorService afuledexecutorService = Executors.NewScheduledThreadpool (1); enderEdexecutorService.ScheduleatFixedRate (new Runnable () {@Override public void run () {if (file.lastModified ()> lastTime) {System.out.Out.println ("Dateiaktualisierung! Zeit:" + Datei.lastModified ();}; TimeUnit.seconds); try {thread.sleep (1000 * 60 * 10); } catch (interruptedException e) {e.printstacktrace (); }}}Im tatsächlichen Test stellte ich fest, dass der obige Code nur dann ausgelöst wurde, wenn die erste Änderung geändert wurde, die Änderung jedoch erneut nutzlos wäre. Das heißt, wenn eine Ausnahme ausgelöst wurde, würde die Zeitaufgabe nicht mehr ausgeführt. Der Hauptgrund für dieses Problem ist, dass der teplanedexecutorservice ist
Schauen Sie sich die Anweisungen zur Quellcode -Kommentaranweisungen von teplanedexecutorservice direkt an
Wenn eine Ausführung der Aufgabe auf eine Ausnahme trifft, werden nachfolgende Hinrichtungen unterdrückt. Anderer ist die Aufgabe nur durch Stornierung oder Beendigung des Testamentsverkehrs.
Wenn Sie diese Haltung verwenden, müssen Sie daher sicherstellen, dass Ihre Aufgabe keine Ausnahmen auswirft
Die entsprechende Lösung ist relativ einfach, fangen Sie sie einfach an
III. Erweiterte Ausgabe
Die vorherige ist eine grundlegende Implementierungsversion. Natürlich gibt es im Java -Kreis im Grunde genommen viele gemeinsame Anforderungen, die entsprechende Open -Source -Tools verwendet werden. Dies ist natürlich keine Ausnahme, und es sollte die Apache -Serie sein, dass jeder mehr Attribute hat.
Zunächst einmal Maven -Abhängigkeiten
<Depopentcy> <gruppe> commons-io </Groupid> <artifactId> commons-io </artifactId> <version> 2.6 </Version> </abhängig>
Hauptsächlich verwenden wir den FileAeAlerationObserver, FilealterationListener und FileAlterationMonitor in diesem Tool, um verwandte Anforderungenszenarien zu implementieren. Natürlich ist es sehr einfach zu bedienen, daher weiß ich nicht, wie ich es erklären soll. Schauen Sie sich den Code an, der von einem meiner Open-Source-Projekte Quick-Alarm kopiert wurde.
public class PropertiesConflistenerHelper {public static boolean RegisterConfChangelistener (Dateidatei, Funktion <Datei, Karte <String, Alarmconfig >> func) {try {// Polling -Intervall 5 Sekunden lang Inval = timeUnit.seconds.tomillis (5); // Da das Zuhören in Verzeichnissen ausgeführt wird, wird das Root -Verzeichnis der Datei hier direkt erhalten. Datei DIR = Datei.getParentFile (); // Erstellen Sie einen Dateibeobachter, um Filter FileAlterationObserver Observer = New FileAlterationObserver (DIR, FileFilterutils.and (FileFilterutils.FileFileFilter (), FileFilterutils.nameFileFilter (Datei.getName ()))); // Datei ändern. Änderung des Listener Observer.addListener (New MyFilelistener (Func)); FilealterationMonitor monitor = neuer filealterationMonitor (Intervall, Beobachter); Monitor.Start (); zurückkehren; } catch (Ausnahme e) {log.Error ("Registereigenschaften ändern Hörer Fehler! E: {}", e); false zurückgeben; }} statische endgültige Klasse MyfilelISTener erweitert FileAlterationListenerAdaptor {private Funktion <Datei, Karte <String, Alarmconfig >> func; public myFilelistener (Funktion <Datei, Karte <String, Alarmconfig >> func) {this.func = func; } @Override public void onFilechange (Dateidatei) {map <string, alarmconfig> ans = func.apply (Datei); // Wenn das Laden fehlschlägt, drucken Sie ein log -log.warn ("PropertiesConfig geändert! Reload Ans: {}", Ans); }}}Für die obige Implementierung einige kurze Erklärungen:
Eine Frage, was passiert, wenn eine Ausnahme ausgelöst wird, wenn die Func -Methode ausgeführt wird?
Die tatsächlichen Testergebnisse sind die gleichen wie oben. Nach einer Ausnahme müssen Sie noch vorsichtig sein und die Ausnahme nicht ausführen.
Schauen wir uns also die obige Implementierungslogik an und ziehen Sie das Kernmodul direkt ab.
public void run () {while (true) {if (this.running) {iterator var1 = this.obServers.iterator (); while (var1.hasnext ()) {FileAlterationObServer Observer = (FileAlterationObServer) var1.Next (); Observer.CheckandNotify (); } if (this.running) {try {thread.sleep (this.interval); } catch (InterruptedException var3) {; } weitermachen; } } zurückkehren; }}Aus dem oben genannten ist im Grunde klar, dass sich die gesamte Implementierungslogik von unserer ersten zeitgesteuerten Aufgabenmethode unterscheidet. Hier verwenden wir Threads und tote Schleifen direkt, und mit Schlafmethoden werden intern innehalten. Wenn eine Ausnahme eintritt, ist es gleich, sie direkt zu werfen, und der Faden knien nach unten.
Ergänzende JDK -Version
JDK1.7 bietet einen Watchservice, mit dem auch Dateiänderungen überwacht werden können. Ich war noch nicht so ausgesetzt, also habe ich herausgefunden, dass es dieses Ding gibt. Dann suchte ich nach den verwendeten Informationen und stellte fest, dass sie recht einfach ist. Ich habe einen Blog-Beitrag gesehen, der erklärt, dass er ereignisgesteuert ist und eine höhere Effizienz hat. Hier ist eine einfache Beispiel -Demo
@Testpublic void testFileUpwather () löst IOException aus (Anweisungen, der Hörer hier muss auch der Verzeichnis paths paths.get ("/tmp") sein; WatchService watcher = fileSystems.getDefault (). NewWatchService (); path.register (Beobachter, Eintrag_Modify); Neuer Thread (() -> {try {while (true) {watchkey key = watcher.take (); für (watchEvent <?> Ereignis: key.pollevents ()) {if (Ereignis.kind () == Überfluss {// Ereignis kann verloren oder verurteilt werden. } if (! key.reset ()) {// Watchkey -Break zurücksetzen; try {thread.sleep (1000 * 60 * 10); } catch (interruptedException e) {e.printstacktrace (); }}Iv. Zusammenfassung
Die Verwendung von JAVA zur Implementierung der Überwachung von Änderungen der Konfigurationsdatei umfasst hauptsächlich zwei Punkte
Insgesamt ist diese Implementierung relativ einfach. Unabhängig davon, ob es sich um eine benutzerdefinierte Implementierung handelt oder sich auf Commos-IO stützt, hat es nicht viele technische Kosten, aber eine zu beachten ist:
Um die obige Situation zu vermeiden, besteht eine Implementierung, die durchgeführt werden kann, um die asynchrone Nachrichtenbenachrichtigung von EventBus zu verwenden. Senden Sie nach Änderungen der Datei eine Nachricht und fügen Sie dann eine @Subscribe -Annotation zur spezifischen Methode zum Nachladen der Dateiinhalte hinzu. Dies realisiert nicht nur die Entkopplung, sondern vermeidet auch Serviceausnahmen, die durch Ausnahmen verursacht werden (wenn Sie an dieser Implementierung interessiert sind, können Sie kommentieren und erklären).
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.