Maison >Java >javaDidacticiel >[Tomcat] Analyse des modèles de conception liés à Tomcat
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.
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 :
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.
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 :
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.
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.
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 :
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 :
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 :
<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 :
<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 :
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.
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.
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 :
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 :
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.
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é.
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 :
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 :
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!