Maison >Java >javaDidacticiel >[Tomcat] Analyse des modèles de conception liés à Tomcat

[Tomcat] Analyse des modèles de conception liés à Tomcat

PHP中文网
PHP中文网original
2017-07-10 18:12:181161parcourir

Mode Façade

Le modèle de façade est utilisé à de nombreux endroits dans Tomcat. Ce modèle de conception est utilisé dans l'encapsulation d'objets Request et Response, l'encapsulation Standard Wrapper vers ServletConfig, ApplicationContext vers ServletContext, etc.

Principes du modèle de conception de façade

Ce modèle de conception a été utilisé à de nombreuses reprises, alors quel rôle ce modèle de conception a-t-il ? Comme son nom l’indique, il s’agit d’encapsuler quelque chose dans une façade pour faciliter la communication avec les autres, tout comme le ministère des Affaires étrangères d’un pays.

Ce modèle de conception est principalement utilisé lorsqu'un grand système est constitué de plusieurs sous-systèmes. Ces sous-systèmes doivent communiquer entre eux, mais chaque sous-système ne peut pas trop exposer ses données internes aux autres systèmes, sinon il ne serait pas nécessaire de se diviser en deux. sous-systèmes. Chaque sous-système concevra une façade pour encapsuler les données intéressant les autres systèmes et y accéder via cette façade. C’est l’objectif du modèle de conception de façade.

Le schéma schématique du modèle de conception de façade est le suivant :

Figure 1. Schéma de la façade

Le client ne peut accéder qu'aux données fournies dans la façade, qui sont la clé du modèle de conception de façade. Quant à la manière dont le client accède à la façade et à la manière dont le sous-système fournit la façade, le modèle de conception de façade ne le stipule pas.

Exemple de mode façade Tomcat

Le modèle de conception de façade est beaucoup utilisé dans Tomcat, car il existe de nombreux composants différents dans Tomcat, et chaque composant doit interagir avec les données. Utiliser le modèle de façade pour isoler les données est un bon moyen.

Voici le modèle de conception de façade utilisé sur demande :

Figure 2. Diagramme de classes du modèle de conception de façade de la demande

Comme le montre la figure, la classe HttpRequestFacade encapsule l'interface HttpRequest pour fournir des données. Les données accessibles via HttpRequestFacade sont transmises par proxy à HttpRequest. Habituellement, les objets encapsulés sont définis sur des modifications d'accès privées ou protégées pour empêcher que Façade ne soit modifiée. accédé directement.

Mode observateur

Ce modèle de conception est également une méthode de conception couramment utilisée. Il est également généralement appelé modèle de publication-abonnement, qui est un mécanisme d'écoute d'événements. Il déclenche généralement certaines opérations avant et après qu'un événement se produise.

Principe du modèle d'observateur

Le principe du mode observateur est également très simple, c'est-à-dire qu'il y a toujours quelqu'un qui vous regarde à côté de vous lorsque vous faites quelque chose qui l'intéresse, il fera autre chose en conséquence. Mais la personne qui vous regarde doit s'inscrire auprès de vous, sinon vous ne pourrez pas la notifier. Le modèle d'observateur comprend généralement les rôles suivants :

  • Subject est le sujet abstrait : il est chargé de gérer les références de tous les observateurs et de définir les principales opérations de l'événement.
  • ConcreteSubject Sujet concret : il implémente toutes les interfaces définies du sujet abstrait lorsqu'il change, il en informera tous les observateurs.
  • Observateur Observer : surveillez l'interface d'opération correspondante pour détecter les changements dans le sujet.

Exemple du mode observateur de Tomcat

Le mode observateur est également utilisé à de nombreux endroits dans Tomcat. Le Lifecycle qui contrôle le cycle de vie des composants mentionné précédemment est l'incarnation de ce mode. Le même principe s'applique à la création d'instances de Servlet, à la gestion de Session, au Conteneur, etc. Ce qui suit examine principalement la mise en œuvre spécifique de Lifecycle.

Diagramme de structure du modèle d'observateur du cycle de vie :

Figure 3. Diagramme de structure du modèle d'observateur du cycle de vie

Dans le diagramme de structure ci-dessus, LifecycleListener représente un observateur abstrait, qui définit une méthode lifecycleEvent, qui est la méthode à exécuter lorsque le thème change. ServerLifecycleListener représente un observateur spécifique. Il implémente les méthodes de l'interface LifecycleListener, qui est l'implémentation spécifique de cet observateur spécifique. L'interface Lifecycle représente un sujet abstrait qui définit les méthodes de gestion des observateurs et les autres méthodes qu'il doit appliquer. StandardServer représente un sujet spécifique, qui implémente toutes les méthodes des sujets abstraits. Ici, Tomcat a étendu l'observateur et ajouté deux autres classes : LifecycleSupport et LifecycleEvent, qui servent de classes auxiliaires pour étendre les fonctions de l'observateur. LifecycleEvent vous permet de définir des catégories d'événements, et différents événements peuvent être traités différemment, ce qui le rend plus flexible. La classe LifecycleSupport représente la gestion du sujet de plusieurs observateurs. Cette gestion est extraite et implémentée de manière uniforme si vous la modifiez à l'avenir, il vous suffit de modifier la classe LifecycleSupport. Il n'est pas nécessaire de modifier tous les sujets spécifiques, car tous les sujets spécifiques. avoir des opérations sur les observateurs délégués à la classe LifecycleSupport. Cela peut être considéré comme une version améliorée du modèle Observer.

Le code de la méthode permettant à LifecycleSupport d'appeler l'observateur est le suivant :

Liste 1. méthode fireLifecycleEvent dans LifecycleSupport
<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>

Comment le thème informe-t-il les observateurs ? Regardez le code ci-dessous :

Listing 2. méthode de démarrage dans le conteneur
<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>

Jetons un œil à cette partie du code dans Tomcat7. L'article précédent disait que le cycle de vie du composant est géré par le conteneur parent contenant le composant. Le processus de démarrage du Service est géré par le Serveur. La classe d'implémentation standard de l'interface serveur est la classe StandardServer, StandardServer implémente la méthode startInernal(), qui est le processus de démarrage cyclique du service géré par StandServer. Les services de Tomcat implémentent tous l'interface Lifecycle, de sorte que les services gérés seront ainsi informés. en exécutant la méthode start(), startIntenal La méthode () est comme ceci :

<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>

Maintenant, tous les services recevront la notification et exécuteront la méthode de démarrage. Si l'utilisation d'un service n'est pas autorisée, une LifecycleException sera levée.

stopIntenal() demandera à tous les services d'exécuter la méthode stop. Le processus de traitement spécifique est similaire à la méthode startIntenal().

La clé de la liste de codes ci-dessus est la méthode fireLifecycleEvent(), et son processus d'exécution est le suivant :

  1. Appelez la méthode fireLifecycleEvent (écouteur LifecycleListener) de LifecycleBase LifecycleBase est une classe abstraite qui implémente l'interface Lifecycle
  2. .
  3. Continuez à appeler la méthode fireLifecycleEvent(String type, Object data) de LifecycleSupport (qui est une classe de notification d'événement auxiliaire pour les auditeurs enregistrés, ne peut pas être héritée, utilisez final)
  4. Notification complète de l'événement

La méthode de fireLifecycleEvent(String type, Object data) est la suivante :

<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>

Ainsi, la notification d'événements spécifiques est complétée par la méthode lifecycleEvent de l'interface LifecycleListener. Chaque classe d'implémentation peut implémenter une logique d'écoute d'événements différente selon différentes situations.

Mode Commande

Les deux composants principaux de Tomcat, Connector et Container, ont été comparés à un couple. L'homme remet la demande acceptée à l'hôtesse sous la forme d'une commande. Correspondant à Connector et Container, Connector appelle également Container via le mode commande.

Principe du mode commande

La fonction principale du mode commande est d'encapsuler les commandes et de séparer la responsabilité de l'émission des commandes de la responsabilité de l'exécution des commandes. C'est aussi une division fonctionnelle du travail. Différents modules peuvent interpréter différemment la même commande.

Voici le mode de commande qui inclut généralement les rôles suivants :

  • Client : Créez une commande et décidez du destinataire
  • Command command : L'interface de commande définit une méthode abstraite
  • ConcreteCommand : Commande spécifique, chargée d'appeler l'opération correspondante du destinataire
  • Demandeur d'invoker : responsable de l'appel de l'objet de commande pour exécuter la requête
  • Récepteur : Responsable de la mise en œuvre et de l'exécution d'une demande

Exemple de mode commande dans Tomcat

Le mode commande dans Tomcat se reflète entre les composants Connecteur et Conteneur. En tant que serveur d'applications, Tomcat recevra sans aucun doute de nombreuses requêtes. Comment distribuer et exécuter ces requêtes est une fonction nécessaire.

Voyons comment Tomcat implémente le mode commande. Voici le diagramme de structure du mode commande Tomcat :

Figure 4. Schéma structurel du mode commande Tomcat

Connector agit comme un demandeur abstrait et HttpConnector agit comme un demandeur concret. HttpProcessor comme commande. Container sert de récepteur abstrait de la commande et ContainerBase sert de récepteur concret. Le client est le composant serveur du serveur d'applications. Le serveur crée d’abord l’objet HttpConnector du demandeur de commande, puis crée l’objet de commande HttpProcessor. Transmettez ensuite l’objet de commande au conteneur ContainerBase destinataire de la commande pour traiter la commande. La commande est finalement exécutée par le conteneur de Tomcat. Les commandes peuvent arriver sous forme de file d'attente et les conteneurs peuvent également gérer les requêtes de différentes manières. Par exemple, le protocole HTTP1.0 et HTTP1.1 seront traités différemment.

Modèle de chaîne de responsabilité

L'un des modèles de conception les plus faciles à découvrir dans Tomcat est le modèle de chaîne de responsabilité. Ce modèle de conception est également la base de la conception du conteneur dans Tomcat. L'ensemble du conteneur est relié entre eux par une chaîne, et cette chaîne passe toujours correctement. demande au traitement final. Le Servlet demandé.

Principe du modèle de chaîne de responsabilité

Le modèle de chaîne de responsabilité est que de nombreux objets ont des références à leurs objets suivants et sont connectés pour former une chaîne. La demande est transmise sur cette chaîne jusqu'à ce qu'un objet de la chaîne gère la demande, ou chaque objet La demande peut être. traité et transmis au suivant jusqu'à ce que chaque objet de la chaîne soit finalement traité. De cette manière, n’importe quel nœud de traitement peut être ajouté à la chaîne sans affecter le client.

Habituellement, le modèle de chaîne de responsabilité comprend les rôles suivants :

  • Handler (gestionnaire abstrait) : définit une interface de traitement des requêtes
  • ConcreteHandler (gestionnaire spécifique) : la classe spécifique qui gère la requête ou la transmet à la personne suivante

Exemple de modèle de chaîne de responsabilité dans Tomcat

Ce modèle de conception est presque entièrement utilisé dans Tomcat. Le paramètre de conteneur de Tomcat est le mode de chaîne de responsabilité Du moteur à l'hôte en passant par le contexte et le wrapper, les requêtes sont transmises via une chaîne.

Le diagramme de structure de classe du modèle de chaîne de responsabilité dans Tomcat est le suivant :

Figure 5. Schéma de structure du modèle de chaîne de responsabilité Tomcat

La figure ci-dessus décrit essentiellement le diagramme de structure de classe de quatre sous-conteneurs utilisant le modèle de chaîne de responsabilité. Les rôles correspondants du modèle de chaîne de responsabilité, le conteneur joue le rôle de processeur abstrait et le processeur spécifique est joué par le sous. -des conteneurs tels que StandardEngine. Contrairement à la chaîne de responsabilité standard, les interfaces Pipeline et Valve sont présentées ici. Que font-ils ?

En effet, Pipeline et Valve ont étendu les fonctions de cette chaîne, leur permettant d'accepter une intervention extérieure lors de la transmission descendante de la chaîne. Le pipeline est le tube qui relie chaque sous-conteneur. Les objets de requête et de réponse passés à l'intérieur sont comme l'eau qui coule dans le tube, et la valve est les petites ouvertures de ce tube, vous donnant la possibilité de toucher l'eau à l'intérieur et de faire un peu plus. des choses.

Afin d'éviter que l'eau ne soit aspirée et ne puisse s'écouler vers le conteneur suivant, il y a toujours un nœud à l'extrémité de chaque section de tuyau pour garantir qu'elle puisse s'écouler vers le sous-conteneur suivant, donc chaque conteneur a une valve StandardXXX. Tant qu’il implique ce type de flux de traitement enchaîné, il s’agit d’un modèle qui mérite d’être étudié.

Aller à :

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn