Reden wir zuerst darüber
Vor kurzem habe ich eine inländische Open Source MySQL -Datenbank Middleware studiert. Nachdem er seine neueste Version des Codes nach Eclipse heruntergezogen hat, damit erfunden und verschiedene Tests und Codeverfolgung durchgeführt werden. Wenn ich es nach der Verwendung schließen möchte, ziehe ich seine Stoppklasse heraus und möchte ihn ausführen. Ich fand, dass in dieser Klasse nur die folgenden Codezeilen geschrieben wurden, also hatte ich das Gefühl, dass ich in einem Augenblick sehr verletzt wurde.
public static void main (String [] args) {System.out.println (neues Datum () + ", Server -Shutdown!"); }Wenn diese Middleware gestartet und ausgeführt wird, ist das Hören aktiviert, viele Threads werden ausgeführt und es gibt viele Socket -Verbindungen. Aber es gibt keine elegante Möglichkeit, es auszuschalten. In der Verzweiflung konnte ich also nur zum kleinen roten Punkt der Sonnenfinsternis gehen und die VM gewaltsam gestoppt.
Wenn es sich um eine Software mit einer guten Architektur, einer klaren und modularen Software, insbesondere einer serverähnlichen Software, ist es sehr wichtig, eine Reihe von Lebenszyklus-Management-Mechanismen zu haben. Es kann nicht nur den Lebenszyklus jedes Moduls verwalten, sondern auch eleganter sein, wenn Sie die gesamte Software starten und stoppen, ohne Ressourcen zu verpassen.
Einfache Implementierung des Lebenszyklusmechanismus
Lebenszykluszustand
Der Lebenszykluszustand eines Moduls hat im Allgemeinen Folgendes:
Neugeborene-> Initialisierung-> Initialisierung abgeschlossen-> Initialisierung-> Initialisierung abgeschlossen-> Initialisierung-> Pausing-> Pausing-> Wiederherstellung-> Erholung-> Zerstören-> Zerstören-> Zerstören. Wenn die Konvertierung zwischen Staaten fehlschlägt, tritt er in einen anderen Zustand ein: Misserfolg.
Dazu können Sie eine Aufzählungsklasse verwenden, um diese Zustände zu zählen, wie unten gezeigt:
public enum lifecyclestate {new, // Newsen -Initialisierung, Initialisierung, Starten initialisieren, gestartet, // Starten, suspendiert, // Pause wieder aufnehmen, wieder aufgenommen, // wiederherstellen, zerstört, zerstört, // zerstört; // fehlgeschlagen}}Schnittstelle
Verschiedene Verhaltensnormen im Lebenszyklus erfordern auch eine Schnittstelle zum Definieren, wie unten gezeigt:
öffentliche Schnittstelle Ilifecycle { / ** * initialisieren * * @throw LifecycleException * / public void init () löscht LifecycleException aus; / ** * start * * @throw LifecycleException */ public void start () löst LebenszyklusException aus; / ** * pause * * @throw LifecycleException */ public void suspend () löscht Lebenszyklusxzeption aus; / ** * erholen * * @throw LifecycleException */ public void resume () löscht LifecycleException aus; / ** * zerstören * * @Throws LifecycleException */ public void zerstören () löst Lebenszyklusxzeption aus; / ** * Lebenszyklus -Hörer hinzufügen * * @param Hörer */ public void addlifecyclelistener (Ilifecyclelistener -Hörer); / ** * Lebenszyklus -Hörer löschen * * @param Hörer */ public void removelifecyclelistener (ilifecyclelistener Hörer);}Wenn ein Übergang des Lebenszykluszustands auftritt, müssen möglicherweise Hörer, die an einer bestimmten Art von Ereignis interessiert sind, möglicherweise ausgelöst werden. Daher definiert Ilifecycle auch zwei Methoden, um die Hörer hinzuzufügen und zu entfernen. Sie sind: öffentliche Leere Addlifecyclelistener (Ilifecyclelistener -Hörer); und public void removelifecyclelistener (Ilifecyclelistener -Hörer);
Der Hörer definiert auch seine Verhaltensnormen durch eine Schnittstelle, wie unten gezeigt:
öffentliche Schnittstelle Ilifecyclelistener { / *** Lebenszyklusereignisse handeln** @param Event Lifecycle Ereignisse* / public void LifecycleEvent (LifecycleEvent Event);}Lebenszyklusereignisse werden wie unten gezeigt durch Lebenszyklus dargestellt:
Public Final Class LifecycleEvent {Private Lifecyclestate State; public LifecycleEvent (LifeCyClestate State) {this.state = STAAT; } / ** * @return the State * / public LifeCyClestate getState () {return state; }}Implementierung von Skelett
Mit der Ilifecycle -Schnittstelle wird jede Klasse, die diese Schnittstelle implementiert, als Lebenszyklus -Management -Objekt verwendet. Diese Klasse kann ein Socket -Hördienst sein oder ein bestimmtes Modul usw. darstellen. Müssen wir also nur ILIfeCycle implementieren? Es kann gesagt werden, dass jedoch in Anbetracht der Tatsache, dass jedes Lebenszyklus -Management -Objekt in verschiedenen Phasen des Lebenszyklus ein gewisses Verhalten hat, wie z. B.:
Setzen Sie Ihren eigenen Lebenszykluszustand fest, um zu überprüfen, ob der Übergang des Staates der Logik entspricht, um den Hörer darüber zu informieren, dass sich der Lebenszykluszustand geändert hat. Daher ist es von großer Bedeutung, eine abstrakte AbstractLifecycle -Klasse als Skelettimplementierung von Ilifecycle zu liefern, was viel doppelter Code vermeidet und die Architektur klarer macht. Diese abstrakte Klasse implementiert alle in Ilifecycle definierten Schnittstellenmethoden und fügt entsprechende abstrakte Methoden für die Implementierung von Unterklassen hinzu. AbstractLifecycle kann so implementiert werden:
public abstract class AbstractLifecycle implementiert ILIfeCycle {private Liste <ilifecyclelistener> listener = new CopyonWriteArrayList <Ilifecyclelistener> (); / *** Zustand repräsentiert den aktuellen Lebenszykluszustand*/ Private Lifecyclestate State = Lifecyclestate.New; / * * @see ilifecycle#init () */ @Override public Final Synchronized void init () löscht LifecycleException {if (state! = lifecyclestate.new) {return; } setStateandFireEvent (LifeCyClestate.initialisierung); try {init0 (); } catch (throwable t) {setStateandFireEvent (LifeCyClestate.Failed); if (t InstanceOf LifecycleException) {throw (LifecycleException) t; } else {werfen neuer Lebenszyklus (FormatString ("nicht initialisieren {0}, Fehler msg: {1}", toString (), t.getMessage ()), t); }} setStateAnDFireeEvent (LifeCyClestate.initialized); } Protected Abstract void init0 () löst Lebenszyklusxzeption aus; / * * @see ilifecycle#start () */ @Override public Final Synchronized void start () löscht LifecycleException {if (state == lifecyclestate.new) {init (); } if (Status! = LifeCyClestate.initialized) {return; } setStateandFireEvent (LifeCyClestate.Starting); versuche {start0 (); } catch (throwable t) {setStateandFireEvent (LifeCyClestate.Failed); if (t InstanceOf LifecycleException) {throw (LifecycleException) t; } else {werfen neuer Lebenszyklus (FormatString ("Start {0}, Fehler msg: {1}", toString (), T.getMessage ()), t); }} setStatEandFireeEvent (LifeCyClestate.started); } Protected Abstract void start0 () löst Lebenszyklusxzeption aus; / * * @see ilifecycle#suspend () */ @override public Final Synchronized void suspend () löst LifecycleException {if (state == lifecyclestate.uspending || state == lifecyclestate.uspended) {return; } if (Status! = LifeCyClestate.started) {return; } setStateandFireEvent (LifeCyClestate.Suspending); try {suspend0 (); } catch (throwable t) {setStateandFireEvent (LifeCyClestate.Failed); if (t InstanceOf LifecycleException) {throw (LifecycleException) t; } else {werfen neuer Lebenszyklus (FormatString ("nicht ausgesetzt {0}, Fehler msg: {1}", toString (), T.getMessage ()), t); }} setStateAndFireeEvent (LifeCyClestate.Suspended); } Protected Abstract void suspend0 () löst Lebenszyklusxzeption aus; / * * @see ilifecycle#resume () */ @Override public Final Synchronized void resume () löscht LifecycleException {if (state! = lifecyclestate.uspended) {return; } setStateandFireEvent (LifeCyClestate.Resuming); try {resume0 (); } catch (throwable t) {setStateandFireEvent (LifeCyClestate.Failed); if (t InstanceOf LifecycleException) {throw (LifecycleException) t; } else {werfen neuer Lebenszyklus (FormatString ("nicht wieder aufgenommen {0}, Fehler msg: {1}", toString (), T.getMessage ()), t); }} setStateandFireeEvent (LifeCyClestate.Resumed); } Protected Abstract void resume0 () löscht Lebenszyklusxzeption aus; / * * @see ilifecycle#destroy () */ @Override public Final Synchronized void Distre Destroy () löst LifecycleException {if (state == lifecyclestate.destroying || state == LifeCyclestate.Destroyed) {return; } setStateandFireEvent (LifeCyClestate.Destroying); probieren {destroy0 (); } catch (throwable t) {setStateandFireEvent (LifeCyClestate.Failed); if (t InstanceOf LifecycleException) {throw (LifecycleException) t; } else {werfen neuer Lebenszyklus (formatString ("nicht zerstören {0}, Fehler msg: {1}", toString (), T.getMessage ()), t); }} setStatEandFireeEvent (LifeCyClestate.Destroyed); } geschützte abstrakte void zerstören0 () löst Lebenszyklusxzeption aus; / * * @see * ilifecycle#Addlifecyclelistener (ilifecyclelistener) */ @Override public void addlifecyclelistener (ilifecyclelistener Hörer) {listener.add (Hörer); } / * * @see * ilifecycle#removelistener (ilifecyclelistener) * / @Override public void removelifecyclelistener (ilifecyclelistener Hörer) {Hörer.Remove (Hörer); } private void FireLifecycleEvent (LifecycleEvent Ereignis) {für (Iterator <ilifecyclelistener> it = lousers.iterator (); hasnext ();) {ilifecyclelistener listener = it.next (); louser.lifecycleEvent (Ereignis); }} geschützte synchronisierte Lebenszyklus -GetState () {Return Status; } private synchronisierte void setStateandFireEvent (LifeCyClestate NewState) löst LifecycleException aus {state = newState; firelifecycleEvent (neuer Lebenszyklus (Zustand)); } private String formatString (String -Muster, Objekt ... Argumente) {return messageFormat.format (Muster, Argumente); } / * * @see java.lang.Object#toString () * / @Override public String toString () {return getClass (). getImpleName (); }}Es ist zu erkennen, dass die Implementierung der abstrakten Klassen -Skelett im Lebenszyklus einige gemeinsame Dinge im Lebenszyklus -Management erledigt und überprüft, ob der Übergang zwischen Staaten legal ist (z. B. muss er vor Beginn init sein), den internen Zustand festlegen und den entsprechenden Hörer auslösen.
Nachdem die abstrakte Klasse die durch Ilifecycle definierte Methode implementiert, lässt sie entsprechende abstrakte Methoden für ihre Unterklasse zum Implementieren. Wie im obigen Code gezeigt, enthalten die abstrakten Methoden die folgenden:
geschützte abstrakte void init0 () löst Lebenszyklusxzeption aus; geschützte abstrakte void start0 () wirft Lebenszyklusxzeption aus; geschützte abstrakte void suspend0 () wirft Lebenszyklusxzeption aus; geschützte abstrakte void resume0 () löst Lebenszyklusxzeption aus; geschützte abstrakte void zerstören0 () wirft Lebenszyklusxzeption aus;
Elegante Implementierung
Bisher haben wir die Schnittstelle iLifecycle definiert, und sein Skelett implementiert abstrakteLifecycle und hat einen Hörermechanismus hinzugefügt. Es scheint, dass wir anfangen können, eine Klasse zu schreiben, um AbstractLifecycle zu erben und die abstrakte Methode, die sie definiert, so weit so gut umschreiben.
Aber bevor wir anfangen, müssen wir mehrere andere Probleme in Betracht ziehen.
Interessieren unsere Implementierungskurse an allen abstrakten Methoden?
Muss jede Implementierung init0, start0, suspend0, resume0, destroy0, destoy0 implementieren?
Unterstützen unsere lebenden Klassen oder Module manchmal keine Suspendierung oder Genesung?
Ein direktes Erben von AbstractLifecycle bedeutet, dass alle seine abstrakten Methoden implementiert werden müssen.
Daher benötigen wir auch eine Standardimplementierung, defaultLifecycle, lassen Sie sie AbstractLifecycle inerit und implementieren alle abstrakten Methoden, aber es tut nichts Praktisches, tun nichts. Lassen Sie uns einfach eine echte Implementierungsklasse erben, die diese Standard -Implementierungsklasse erben und die Interessenmethode überschreiben.
Also wurde unser Standardlifecycle geboren:
öffentliche Klasse Standardlifecycle erweitert AbstractLifecycle { / * * @see contractLifecycle#init0 () * /@Override Protected void init0 () löscht LifecycleException aus {// nichts} / * * @see AbstractLifeCycle#start0 () * /@Override -protected void void void void0 () throws lifescycle# /@Override proted void void void void0 () throws lifescycle# /@Override @override protoid void void void void0 () throws lifescycle# /@Override proted void void void void Void void 0 () throws lifowcycle#) * @see AbstractLifecycle#suspend0 () * / @Override geschützt void suspendinternal () löst Lebenszyklus aus {// nichts} / * * @see AbstractLifeCycle#Resume0 () * / @Override Protected Void Resume0 () Liftecycle #0 / // // // // // // // // // // // // // // // // // // // // // // // // // // // / / / // // / / / // / / / // / / // // // // // // // / / @Override */ @Override Protected void Destroy0 () löscht LebenszyklusException {// nichts}} aus Für Standardlifecycle ist nichts seine Verantwortung.
Als nächstes können wir unsere eigene Implementierungsklasse schreiben, defaultLifecycle erben und diese interessierenden Lebenszyklusmethoden neu schreiben.
Zum Beispiel habe ich eine Klasse, die nur einige Aufgaben während der Initialisierung, Startup und Zerstörung ausführen muss, damit ich sie so schreiben kann:
importieren java.io.ioxception; import java.net.serversocket; import java.net.socket; public class SocketServer erweitert defaultLifecycle {private serversocket acapitor = null; privater int port = 9527; / * * @see defaultLifecycle#init0 () */ @Override Protected void init0 () löscht LebenszyklusException {try {ACCEPTOR = New ServerSocket (Port); } catch (ioException e) {werfen neuer Lebenszyklus (e); }} / * * @see defaultLifecycle#start0 () * / @Override Protected void start0 () löscht LifecycleException {Socket Socket = null; try {socket = ACCEPTOR.Accept (); // etwas mit Socket} catch (ioException e) {neue Lebenszyklus -Exception (e) werfen; } endlich {if (socket! = null) {try {socket.close (); } catch (ioException e) {// Todo automatisch generierter Catch-Block e.printstacktrace (); }}}}} / * * @see DefaultLifecycle#Comre0 () * / @Override Protected void Destroy0 () löscht LebenszyklusException {if (actecessor! } catch (ioException e) {// Todo automatisch generierter Catch-Block e.printstacktrace (); }}}} In ServerSocket init0 initialisiert Socket -Listening, Start0 beginnt mit der Steckdose, zerstören Sie das Hören von Sockel.
Unter diesem Mechanismus des Lebenszyklusmanagements werden wir Ressourcen problemlos verwalten, und es wird keine Ressourcenabschaltung geben, und die Architektur und Modularität werden klarer.
Ende
Bisher hat dieser Artikel einen einfachen Lebenszyklus -Management -Mechanismus implementiert und alle Implementierungscodes gegeben. Danach wird der gesamte Quellcode auf GitHub platziert. Bitte achten Sie auf die Aktualisierung dieses Artikels.