Why does tomcat source code look like this?

rucheng zhang
5 min readMar 25, 2022

--

Part II, the container in the tomcat

What is a tomcat container

If you have read the first part, you should understand why we need the container in tomcat. Basically, we hope there’s such kind of component that can dynamically load the compiled java classes. Besides, it can handle any ServletRequest.

Let’s take a look at the definition of the Tomcat Container interface, here I only pick some key APIs that are very important.

public interface Container extends Lifecycle {     public Pipeline getPipeline();     public Container getParent();

public void backgroundProcess();
public void addChild(Container child);}

Before understanding why the tomcat’s container interface looks like this, let’s figure out what kind of issues does the tomcat needs to solve.

Key problems

Let’s take a glance at the URLs we used in our daily work, notice that there’re several items in the URL, HTTP protocol as the beginning, continued with the domain name and port, then will be the service name, then the path behind the service.

http://www.sub1.example.com:8080/service1/app/add
https://www.sub1.example.com:8080/service1/app/delete
http://www.sub2.example.com:8080/service2/app/simple
https://www.sub2.example.com:8443/service2/app/admin

The goal is to dispatch the request to the corresponding servelet to handle. Recall that the tomcat Service has several Connectors for multi ports, and the Processor component for HTTP protocol processing as well. The rest problems that need to be solved in during the URL processing can be described as follows.

  • Some domain names may have some alias domain names, in which case these domain names should be mapped to the same servelet, so we need a component to maintain this. (Host)
  • For different services that may be owned by the same web app, e.g., the admin service and common business service belong to the same web app, so we need a kind of container to hold these services. (Context)

From the common design rule, we usually wrap the raw servelet to enrich the features for easy maintenance.

Design tomcat container step by step

  1. According to the above description, the first version of the tomcat container should look like this.

Here comes another question, how to propagate the request from the outside container to the inside one, and we need to do something in each container. We will introduce a classical design pattern used in tomcat here, the Pipeline or Chain of Responsibility design pattern, which means each pipe in the chain plays a key role in processing the request and response. The pipeline design pattern is somewhat like a stack, each pipe in the pipeline will be recursively invoked.

public interface Pipeline extends Contained {
public void addValve(Valve valve);
public Valve getBasic();
public void setBasic(Valve valve);
public Valve getFirst();
}
public interface Valve {
public Valve getNext();
public void setNext(Valve valve);
public void invoke(Request request, Response response)
}

Notice that, each container inside the tomcat has a pipeline that is chained by a couple of Valves, and the pipeline itself can also be connected with each other. For the Valve pipeline, it has a head and tail named as First and Basic respectively, each parent container will invoke its child’s first Valve in the pipeline.

context.getPipeline().getFirst().invoke(request, response);

Before invoking the service method in Servelet, the Wrapper’s basic valve will invoke the filter chain, where we can do some business logic, e.g, authentication, schema validation, and so on. The following code is a pice part of the StandardWrapperValve invoke method.

public final void invoke(Request request, Response response)
throws IOException, ServletException {
//create a filter chain
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
//do filter
filterChain.doFilter(request.getRequest(),response.getResponse());
}

what’s the difference between Valve pipeline and FilterChain?

The valve belongs to the tomcat framework, while the filter chain is designed for the user. The valve will be invoked whenever a request comes.

2. As a container, what if I want to periodically execute some task, dynamic load the configuration, or load the compiled class files?

The tomcat introduces the backgroundProcess API in the container to do such kinds of things, for example, reload the new compiled serverlet classes to dynamically update web services.

3. How tomcat can dynamically reload classes or configurations? To be more specific what the tomcat framework should do to deal with the in-processing requests, the upcoming requests during that period, what will these components do when different state changes and the different event happens?

A classic design pattern should be the observer model design pattern, whenever the state changes or events happen, the observers will take action.

We should have a LifeCycle interface to let the component have the lifecycle attribute to determine what to do when different state stages. We also have a couple of Listeners to observe the events when state updates. Both of these two interfaces are the infrastructure when implementing a state machine.

Let’s take a look at the tomcat state machine class UML map. The blue line shows the one-one and one-many mapping relationships.

From the picture above, we can see that all the core components of the tomcat have the ability of lifecycle management since they have implemented the LifeCycle interface.

Besides, the blue line shows the inheritance relationship, the parents have the authority to maintain the Lifecycle of their children, e.g., start or stop the children components.

In addition, these components will fire different kinds of lifecycle event when different state happens to the observers, and they will take corresponding actions, for example, publishing messages by email or phone to the customers.

Conclusion

The whole core class UML view of tomcat can be summarized as follows, the blue line shows the data flow, this is one roadmap for you when reading or studying the tomcat source code.

The tomcat source code is classic and has a bit of complexity, if you patiently take some time reading it, you will earn a lot.

--

--