Heim >Java >javaLernprogramm >[Tomcat] Analyse Tomcat-bezogener Entwurfsmuster
Das Fassadenmuster wird an vielen Stellen in Tomcat verwendet. Dieses Entwurfsmuster wird in der Kapselung von Anforderungs- und Antwortobjekten, der Kapselung von Standard-Wrapper zu ServletConfig, der Kapselung von ApplicationContext zu ServletContext usw. verwendet.
Dieses Designmuster wurde bei so vielen Gelegenheiten verwendet. Welche Rolle spielt dieses Designmuster? Wie der Name schon sagt, geht es darum, etwas in eine Fassade einzukapseln, um die Kommunikation mit anderen zu erleichtern, genau wie das Außenministerium eines Landes.
Dieses Entwurfsmuster wird hauptsächlich verwendet, wenn ein großes System aus mehreren Subsystemen besteht, die miteinander kommunizieren müssen, aber jedes Subsystem seine internen Daten nicht zu stark für andere Systeme offenlegen kann, da sonst keine Aufteilung erforderlich wäre Subsysteme. Jedes Subsystem entwirft eine Fassade, um die für andere Systeme interessanten Daten zu kapseln und über diese Fassade darauf zuzugreifen. Dies ist der Zweck des Fassadengestaltungsmusters.
Das schematische Diagramm des Fassadengestaltungsmodells sieht wie folgt aus:
Der Kunde kann nur auf die in der Fassade bereitgestellten Daten zugreifen, die den Schlüssel zum Fassadenentwurfsmuster darstellen. Wie der Kunde auf die Fassade zugreift und wie das Subsystem die Fassade bereitstellt, legt das Fassadenentwurfsmuster nicht fest.
Das Fassadenentwurfsmuster wird häufig in Tomcat verwendet, da es in Tomcat viele verschiedene Komponenten gibt und jede Komponente Daten miteinander interagieren muss. Die Verwendung des Fassadenmusters zum Isolieren von Daten ist eine gute Möglichkeit.
Das Folgende ist das auf Anfrage verwendete Fassadengestaltungsmuster:
Wie aus der Abbildung ersichtlich ist, kapselt die HttpRequestFacade-Klasse die HttpRequest-Schnittstelle, um Daten bereitzustellen, auf die über HttpRequestFacade zugegriffen wird. Normalerweise werden die gekapselten Objekte auf private oder geschützte Zugriffsänderungen gesetzt, um zu verhindern, dass direkt auf Façade zugegriffen wird .
Dieses Entwurfsmuster ist auch eine häufig verwendete Entwurfsmethode. Es wird normalerweise auch als Publish-Subscribe-Muster bezeichnet und ist ein Ereignisüberwachungsmechanismus. Es löst normalerweise einige Vorgänge vor und nach dem Eintreten eines Ereignisses aus.
Das Prinzip des Beobachtermodus ist ebenfalls sehr einfach, das heißt, es ist immer jemand neben Ihnen, der Sie beobachtet, wenn Sie etwas tun, das ihn interessiert, und er wird andere Dinge entsprechend tun. Aber die Person, die Sie anstarrt, muss sich bei Ihnen registrieren, sonst können Sie sie nicht benachrichtigen. Das Beobachtermuster umfasst normalerweise die folgenden Rollen:
Der Beobachtermodus wird auch an vielen Stellen in Tomcat verwendet. Der zuvor erwähnte Lebenszyklus ist die Verkörperung dieses Modus. Das gleiche Prinzip gilt für die Erstellung von Servlet-Instanzen, die Sitzungsverwaltung, den Container usw. Im Folgenden wird hauptsächlich die spezifische Implementierung von Lifecycle betrachtet.
Strukturdiagramm des Beobachtermusters von Lifecycle:
Im obigen Strukturdiagramm stellt LifecycleListener einen abstrakten Beobachter dar, der eine LifecycleEvent-Methode definiert, also die Methode, die ausgeführt werden soll, wenn sich das Thema ändert. ServerLifecycleListener stellt einen bestimmten Beobachter dar. Er implementiert die Methoden der LifecycleListener-Schnittstelle, die die spezifische Implementierung dieses bestimmten Beobachters darstellt. Die Lifecycle-Schnittstelle stellt ein abstraktes Subjekt dar, das Methoden zur Verwaltung von Beobachtern und andere zu erledigende Methoden definiert. StandardServer stellt ein bestimmtes Thema dar, das alle Methoden abstrakter Themen implementiert. Hier hat Tomcat den Beobachter erweitert und zwei weitere Klassen hinzugefügt: LifecycleSupport und LifecycleEvent, die als Hilfsklassen zur Erweiterung der Funktionen des Beobachters dienen. Mit LifecycleEvent können Sie Ereigniskategorien definieren und verschiedene Ereignisse unterschiedlich verarbeiten, was die Flexibilität erhöht. Die LifecycleSupport-Klasse stellt die Verwaltung mehrerer Beobachter dar. Wenn Sie sie in Zukunft ändern, müssen Sie nicht alle spezifischen Themen ändern haben Operationen für Beobachter, die an die LifecycleSupport-Klasse delegiert sind. Dies kann als verbesserte Version des Observer-Musters betrachtet werden.
Der Methodencode von LifecycleSupport zum Aufrufen von Beobachtern lautet wie folgt:
<span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> fireLifecycleEvent(String type, Object data) { LifecycleEvent event </span>= <span style="color: #0000ff">new</span><span style="color: #000000"> LifecycleEvent(lifecycle, type, data); LifecycleListener interested[] </span>= <span style="color: #0000ff">null</span><span style="color: #000000">; </span><span style="color: #0000ff">synchronized</span><span style="color: #000000"> (listeners) { interested </span>=<span style="color: #000000"> (LifecycleListener[]) listeners.clone(); } </span><span style="color: #0000ff">for</span> (<span style="color: #0000ff">int</span> i = 0; i < interested.length; i++<span style="color: #000000">) interested[i].lifecycleEvent(event); }</span>
Wie benachrichtigt das Thema Beobachter? Schauen Sie sich den folgenden Code an:
<span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> start() <span style="color: #0000ff">throws</span><span style="color: #000000"> LifecycleException { lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, </span><span style="color: #0000ff">null</span><span style="color: #000000">); lifecycle.fireLifecycleEvent(START_EVENT, </span><span style="color: #0000ff">null</span><span style="color: #000000">); started </span>= <span style="color: #0000ff">true</span><span style="color: #000000">; </span><span style="color: #0000ff">synchronized</span><span style="color: #000000"> (services) { </span><span style="color: #0000ff">for</span> (<span style="color: #0000ff">int</span> i = 0; i < services.length; i++<span style="color: #000000">) { </span><span style="color: #0000ff">if</span> (services[i] <span style="color: #0000ff">instanceof</span><span style="color: #000000"> Lifecycle) ((Lifecycle) services[i]).start(); } } lifecycle.fireLifecycleEvent(AFTER_START_EVENT, </span><span style="color: #0000ff">null</span><span style="color: #000000">); }</span>
Werfen wir einen Blick auf diesen Teil des Codes in Tomcat7, der besagt, dass der Lebenszyklus der Komponente vom übergeordneten Container verwaltet wird, der die Komponente enthält Die Standardimplementierungsklasse der Serverschnittstelle ist die StandardServer-Klasse. StandardServer implementiert die startInernal()-Methode, bei der es sich um den Prozess des zyklischen Startens des von StandServer verwalteten Dienstes handelt. Alle Dienste implementieren die Lifecycle-Schnittstelle, sodass die verwalteten Dienste dadurch benachrichtigt werden Ausführen der start()-Methode, startIntenal Die ()-Methode sieht so aus:
<span style="color: #008000">/**</span><span style="color: #008000"> * Start nested components ({</span><span style="color: #808080">@link</span><span style="color: #008000"> Service}s) and implement the requirements * of {</span><span style="color: #808080">@link</span><span style="color: #008000"> org.apache.catalina.util.LifecycleBase#startInternal()}. * * </span><span style="color: #808080">@exception</span><span style="color: #008000"> LifecycleException if this component detects a fatal error * that prevents this component from being used </span><span style="color: #008000">*/</span><span style="color: #000000"> @Override </span><span style="color: #0000ff">protected</span> <span style="color: #0000ff">void</span> startInternal() <span style="color: #0000ff">throws</span><span style="color: #000000"> LifecycleException { fireLifecycleEvent(CONFIGURE_START_EVENT, </span><span style="color: #0000ff">null</span><span style="color: #000000">); setState(LifecycleState.STARTING); globalNamingResources.start(); </span><span style="color: #008000">//</span><span style="color: #008000"> Start our defined Services</span> <span style="color: #0000ff">synchronized</span><span style="color: #000000"> (services) { </span><span style="color: #0000ff">for</span> (<span style="color: #0000ff">int</span> i = 0; i < services.length; i++<span style="color: #000000">) { services[i].start(); } } }</span>
Jetzt erhalten alle Dienste die Benachrichtigung und führen die Startmethode aus. Wenn ein Dienst nicht verwendet werden darf, wird eine LifecycleException ausgelöst.
stopIntenal() benachrichtigt alle Dienste, die Stop-Methode auszuführen. Der spezifische Verarbeitungsprozess ähnelt der startIntenal()-Methode.
Der Schlüssel zur obigen Codeliste ist die Methode fireLifecycleEvent(), und ihr Ausführungsprozess ist wie folgt:
Die Methode von fireLifecycleEvent(String-Typ, Objektdaten) lautet wie folgt:
<span style="color: #008000">/**</span><span style="color: #008000"> * Notify all lifecycle event listeners that a particular event has * occurred for this Container. The default implementation performs * this notification synchronously using the calling thread. * * </span><span style="color: #808080">@param</span><span style="color: #008000"> type Event type * </span><span style="color: #808080">@param</span><span style="color: #008000"> data Event data </span><span style="color: #008000">*/</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> fireLifecycleEvent(String type, Object data) { LifecycleEvent event </span>= <span style="color: #0000ff">new</span><span style="color: #000000"> LifecycleEvent(lifecycle, type, data); LifecycleListener interested[] </span>=<span style="color: #000000"> listeners; </span><span style="color: #0000ff">for</span> (<span style="color: #0000ff">int</span> i = 0; i < interested.length; i++<span style="color: #000000">) interested[i].lifecycleEvent(event); }</span>
Die Benachrichtigung über bestimmte Ereignisse wird also durch die lifecycleEvent-Methode der LifecycleListener-Schnittstelle vervollständigt. Jede Implementierungsklasse kann je nach Situation unterschiedliche Ereignisüberwachungslogik implementieren.
Die beiden Kernkomponenten von Tomcat, Connector und Container, wurden mit einem Paar verglichen. Der Mann wird der Gastgeberin die angenommene Bitte in Form eines Befehls übermitteln. Entsprechend Connector und Container ruft Connector Container auch über den Befehlsmodus auf.
Die Hauptfunktion des Befehlsmodus besteht darin, Befehle zu kapseln und die Verantwortung für die Ausgabe von Befehlen von der Verantwortung für die Ausführung von Befehlen zu trennen. Es handelt sich auch um eine funktionale Arbeitsteilung. Verschiedene Module können denselben Befehl unterschiedlich interpretieren.
Das Folgende ist der Befehlsmodus, der normalerweise die folgenden Rollen umfasst:
Der Befehlsmodus in Tomcat spiegelt sich zwischen den Connector- und Container-Komponenten wider. Als Anwendungsserver wird Tomcat zweifellos viele Anfragen empfangen.
Sehen wir uns an, wie Tomcat den Befehlsmodus implementiert. Das Folgende ist das Strukturdiagramm des Tomcat-Befehlsmodus:
Connector fungiert als abstrakter Anforderer und HttpConnector fungiert als konkreter Anforderer. HttpProcessor als Befehl. Container dient als abstrakter Empfänger des Befehls und ContainerBase als konkreter Empfänger. Der Client ist die Serverkomponente des Anwendungsservers. Der Server erstellt zunächst das Befehlsanforderer-HttpConnector-Objekt und dann das Befehls-HttpProcessor-Befehlsobjekt. Das Befehlsobjekt wird dann an den ContainerBase-Container des Befehlsempfängers übergeben, um den Befehl zu verarbeiten. Der Befehl wird letztendlich vom Tomcat-Container ausgeführt. Befehle können als Warteschlange eingehen, und Container können Anfragen auch auf unterschiedliche Weise verarbeiten. Beispielsweise werden das HTTP1.0-Protokoll und HTTP1.1 unterschiedlich gehandhabt.
Eines der am einfachsten zu entdeckenden Entwurfsmuster in Tomcat ist das Chain-of-Responsibility-Muster. Dieses Entwurfsmuster ist auch die Grundlage des Containerdesigns in Tomcat. Der gesamte Container ist durch eine Kette miteinander verbunden, und diese Kette durchläuft das Anfrage zur endgültigen Verarbeitung.
Das Verantwortungskettenmodell besteht darin, dass viele Objekte einen Verweis auf jedes Objekt haben und zu einer Kette verbunden sind. Die Anforderung wird in dieser Kette weitergeleitet, bis ein Objekt in der Kette die Anforderung verarbeitet, oder jedes Objekt Die Anforderung kann sein verarbeitet und an das nächste weitergegeben, bis schließlich jedes Objekt in der Kette verarbeitet ist. Auf diese Weise kann jeder Verarbeitungsknoten zur Kette hinzugefügt werden, ohne dass sich dies auf den Client auswirkt.
Normalerweise umfasst das Chain-of-Responsibility-Modell die folgenden Rollen:
Dieses Entwurfsmuster wird fast vollständig in Tomcat verwendet. Die Containereinstellung von Tomcat ist der Chain-of-Responsibility-Modus. Anforderungen werden über eine Kette weitergeleitet.
Das Klassenstrukturdiagramm des Chain-of-Responsibility-Modells in Tomcat sieht wie folgt aus:
Die obige Abbildung beschreibt im Wesentlichen das Klassenstrukturdiagramm von vier Untercontainern unter Verwendung des Verantwortungskettenmodells. Die entsprechenden Rollen des Verantwortungskettenmodells: Der Container spielt die Rolle eines abstrakten Prozessors, und der spezifische Prozessor wird von Untercontainern gespielt -Container wie StandardEngine. Abweichend von der Standardverantwortungskette werden hier die Schnittstellen Pipeline und Ventil vorgestellt. Was machen sie?
Tatsächlich haben Pipeline und Valve die Funktionen dieser Kette erweitert, sodass sie externe Eingriffe während der Abwärtsübertragung der Kette akzeptieren können. Die Pipeline ist die Röhre, die jeden Untercontainer verbindet. Die darin geleiteten Anforderungs- und Antwortobjekte ähneln dem in der Röhre fließenden Wasser, und das Ventil sind die kleinen Öffnungen in dieser Röhre, die Ihnen die Möglichkeit geben, das Wasser im Inneren zu berühren und etwas Besonderes zu tun Dinge. Dinge.
Um zu verhindern, dass Wasser austritt und nicht zum nächsten Behälter fließen kann, befindet sich am Ende jedes Rohrabschnitts immer ein Knotenpunkt, der dafür sorgt, dass das Wasser zum nächsten Unterbehälter, also jedem Behälter, fließen kann hat ein StandardXXXVentil. Solange es sich um einen solchen verketteten Verarbeitungsablauf handelt, ist dies ein Modell, von dem es sich zu lernen lohnt.
Gehe zu:
Das obige ist der detaillierte Inhalt von[Tomcat] Analyse Tomcat-bezogener Entwurfsmuster. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!