Home >Java >javaTutorial >[Tomcat] Analysis of Tomcat related design patterns
The facade pattern is used in many places in Tomcat. This design pattern is used in Request and Response object encapsulation, Standard Wrapper to ServletConfig encapsulation, ApplicationContext to ServletContext encapsulation, etc.
This design pattern has been used on so many occasions, so what role does this design pattern have? As the name suggests, it is to encapsulate something into a facade to make it easier to communicate with others, just like the Ministry of Foreign Affairs of a country.
This design pattern is mainly used when a large system consists of multiple subsystems. These subsystems must involve mutual communication, but each subsystem cannot expose its own internal data to others too much. system, otherwise there would be no need to divide into subsystems. Each subsystem will design a facade to encapsulate the data of interest to other systems and access it through this facade. This is the purpose of the facade design pattern.
The schematic diagram of the facade design pattern is as follows:
Client can only access the data provided in the Façade, which is the key to the façade design pattern. As for how the Client accesses the Façade and how the Subsystem provides the Façade, the façade design pattern does not stipulate.
The facade design pattern is used a lot in Tomcat, because there are many different components in Tomcat, and each component needs to interact with each other. Using the facade pattern to isolate data is a good way.
The following is the facade design pattern used on Request:
It can be seen from the figure that the HttpRequestFacade class encapsulates the HttpRequest interface to provide data. The data accessed through the HttpRequestFacade is proxied to the HttpRequest. Usually the encapsulated objects are set to Private or Protected access modifications to prevent Façade is accessed directly.
This design pattern is also a commonly used design method. It is also usually called the publish-subscribe pattern, which is the event listening mechanism. It usually triggers some operations before and after an event occurs.
The principle of the observer mode is also very simple, that is, there is always someone watching you next to you when you are doing something. When you do something that interests it, it will do other things accordingly. But the person staring at you must register with you, otherwise you cannot notify it. The observer pattern usually includes the following roles:
The observer mode is also used in many places in Tomcat. The Lifecycle that controls the component life cycle mentioned earlier is the embodiment of this mode. The same principle applies to the creation of Servlet instances, Session management, Container, etc. The following mainly looks at the specific implementation of Lifecycle.
Lifecycle’s observer pattern structure diagram:
In the above structure diagram, LifecycleListener represents an abstract observer, which defines a lifecycleEvent method. This method is the method to be executed when the theme changes. ServerLifecycleListener represents a specific observer. It implements the methods of the LifecycleListener interface, which is the specific implementation method of this specific observer. The Lifecycle interface represents an abstract subject that defines methods for managing observers and other methods it has to do. StandardServer represents a specific topic, which implements all methods of abstract topics. Here Tomcat has extended the observer and added two other classes: LifecycleSupport and LifecycleEvent, which serve as auxiliary classes to extend the functions of the observer. LifecycleEvent allows you to define event categories, and different events can be processed differently, making it more flexible. The LifecycleSupport class represents the topic's management of multiple observers. This management is extracted and implemented uniformly. If you modify it in the future, you only need to modify the LifecycleSupport class. There is no need to modify all specific topics, because all specific topics have operations on observers. Delegated to the LifecycleSupport class. This can be thought of as an improved version of the Observer pattern.
LifecycleSupport's method code for calling the observer is as follows:
<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>
How does the topic notify observers? Look at the code below:
<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>
Let’s take a look at this part of the code in Tomcat7. The previous article said that the life cycle of the component is managed by the parent container containing the component. The startup process of the Service is managed by the Server. The standard implementation class of the Server interface is StandardServer class, StandardServer implements the startInernal() method, which is the process of cyclically starting the Service managed by the StandServer. Tomcat's Services all implement the Lifecycle interface, so the managed Services will be notified, thereby executing the start() method, startIntenal () method is like this:
<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>
Now all Services will receive the notification and then execute the start method. If a Service is not allowed to be used, a LifecycleException will be thrown.
stopIntenal() will notify all Services to execute the stop method. The specific processing process is similar to the startIntenal() method.
The key to the above code list lies in the fireLifecycleEvent() method, and its execution process is as follows:
The method of fireLifecycleEvent(String type, Object data) is as follows:
<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>
So, the notification of specific events is completed by the lifecycleEvent method of the LifecycleListener interface. Each implementation class can implement different event listening logic according to different situations.
Earlier, the two core components of Tomcat, Connector and Container, were compared to a couple. The man will give the accepted request to the hostess in the form of a command. Corresponding to Connector and Container, Connector also calls Container through command mode.
The main function of the command mode is to encapsulate the command and separate the responsibility of issuing the command from the responsibility of executing the command. It is also a functional division of labor. Different modules can interpret the same command differently.
The following is the command mode that usually includes the following roles:
The command mode in Tomcat is reflected between the Connector and Container components. As an application server, Tomcat will undoubtedly receive many requests. How to distribute and execute these requests is a necessary function.
Let’s take a look at how Tomcat implements the command mode. The following is the structure diagram of the Tomcat command mode:
Connector acts as an abstract requester, and HttpConnector acts as a concrete requester. HttpProcessor as command. Container serves as the abstract receiver of the command, and ContainerBase serves as the concrete receiver. The client is the application server Server component. Server first creates the command requester HttpConnector object, and then creates the command HttpProcessor command object. The command object is then handed over to the command recipient ContainerBase container to process the command. The command is ultimately executed by Tomcat's Container. Commands can come in as queues, and Containers can also handle requests in different ways. For example, the HTTP1.0 protocol and HTTP1.1 will be handled differently.
One of the easiest design patterns to discover in Tomcat is the chain of responsibility pattern. This design pattern is also the basis of Container design in Tomcat. The entire container is connected together through a chain, and this chain always correctly passes the request to the final processing. The requested Servlet.
The chain of responsibility model is that many objects have references to their next objects and are connected to form a chain. The request is passed on this chain until an object on the chain handles the request, or each object The request can be processed and passed to the next one until eventually every object in the chain is processed. In this way, any processing node can be added to the chain without affecting the client.
Usually the chain of responsibility model includes the following roles:
This design pattern is almost completely used in tomcat. The container setting of tomcat is the chain of responsibility mode. From Engine to Host to Context to Wrapper, requests are passed through a chain.
The class structure diagram of the chain of responsibility model in Tomcat is as follows:
The above figure basically describes the class structure diagram of four sub-containers using the chain of responsibility model. The corresponding roles of the chain of responsibility model, Container plays the role of abstract processor, and the specific processor is played by sub-containers such as StandardEngine. Different from the standard chain of responsibility, the Pipeline and Valve interfaces are introduced here. What do they do?
In fact, Pipeline and Valve have expanded the functionality of this chain, allowing them to accept outside intervention during the chain's downward transmission. Pipeline is the tube that connects each sub-container. The Request and Response objects passed inside are like the water flowing in the tube, and Valve is the small openings in this tube, giving you the opportunity to touch the water inside and do some extra things. things.
In order to prevent water from being led out and unable to flow to the next container, there is always a node at the end of each section of pipe to ensure that it can flow to the next sub-container, so each container has a StandardXXXValve. As long as it involves this kind of chained processing flow, this is a model worth learning from.
Go to:
The above is the detailed content of [Tomcat] Analysis of Tomcat related design patterns. For more information, please follow other related articles on the PHP Chinese website!