TOMCAT source code analysis and startup process

Foreword:
   This article is some of my experience after reading the TOMCAT source code. It mainly explains the system framework of TOMCAT and the startup process. If there are any mistakes, please criticize and advise!
Suggestion:
   After all, the framework of TOMCAT is still relatively complex, and it is not so easy to grasp the framework of TOMCAT just from the text. So practice, practice, practice. It is recommended to download a source code of TOMCAT, debug it, and then single-step its startup process. If there is something you don't understand, read this article again to see if you can get help. I believe that the effect and learning speed will be much better!
   
1. The overall framework of
   Tomcat The basic framework of Tomcat is divided into four levels.
   Top Level Elements:
    Server
    Service   
   Connector
    HTTP
    AJP
   Container
   Engine
     Host
   Context
   Component  
    manager
   logger
   loader
   pipeline
   valve
         ...
   Standing at the top of the framework are Server and Service
   Server: It is actually the BackGround program. The use of Server in Tomcat is to start and monitor server events (such as restart, shutdown and other commands. In tomcat's standard configuration file: server.xml, we can see "<Server port= "8005" shutdown="SHUTDOWN" debug="0">;" "SHUTDOWN" here is the command word used by the server when monitoring server events), mainly using socket programming in java.
   Service: in tomcat Inside, service refers to a solution to a class of problems. Usually we will use the service provided by tomcat by default: Tomcat-Standalone mode. In this way, the service not only provides us with the service of parsing jsp and servlet, but also provides us with the service of parsing static text.
   
   Connector: Tomcat handles problems in the container, and where does the container get the input information?
Connector is dedicated to this. He will encapsulate the data passed from the socket (information requested by the user through the browser) into a Request and pass it to the container for processing.
   Usually we will use two kinds of Connectors, one is called http connectoer, which is used to pass http requirements. The other is called AJP. When we integrate apache and tomcat, the interaction between apache and tomcat is through this protocol. (Speaking of the integration of apache and tomcat, usually our purpose is to let apache obtain static resources, and let tomcat parse dynamic jsp or servlet.)
   Container: When the http connector passes the requirements to the top-level container:
   In the Container layer, we include 3 kinds of containers: Engin, Host, Context.
   Engin: After receiving the request from the service, after processing, it returns the result to the service (the service interacts with the Engin through the medium of the connector).
   Host: After Engin receives the request from the service, it will not process it by itself, but will hand it over to the appropriate Host for processing.
Host here means virtual host, usually we only use one host, that is, the "localhost" local machine for processing.    Context: After the Host receives the request from the Host, it will not handle it by itself, but will hand it over to the appropriate Context for processing.    For example: <http://127.0.0.1:8080/foo/index.jsp>; <http:    //127.0.1          :8080/bar/index.jsp>; Give bar this Context to handle.    It's obvious! The meaning of context is actually the meaning of a web app.    We usually do this configuration in server.xml    <Context path="/foo" docBase="D:/project/foo/web" />;    this context container is used to do what we should do local.    Compenent: Next, let's talk about what components are used for.    We must first understand the relationship between containers and components. 
 







   


   The request is passed to the container, and when appropriate, it is passed to the next container for processing.
   The container contains various components, which can be understood as providing various value-added services.
   manager: When the manager component is installed in a container, the container supports session management. In fact, the session management in tomcat relies on the manager component installed in the context.
   logger: When a container is installed with the logger component After that, what happens in this container is recorded by this component! We usually see catalina_log.time.txt in the logs/ directory as well as localhost.time.txt and localhost_examples_log.time.txt. This is because we have installed the logger component for the three containers: engine, host and context (examples). This is also the default installation, also known as the standard configuration:)
   loader: The loader component is usually only used for our context container, The loader is used to start the context and manage the classloader of the context.
    pipline: pipeline is such a thing, when a container decides to pass the requirement passed from the superior to the sub-container, it puts the requirement into the pipeline of the container. When the demand flows in the pipeline, it will be intercepted by various valves in the pipeline. For example, there are two valves in the pipeline. The first valve is called "access_allow_vavle", that is to say, when the demand flows, it will see which IP the demand comes from. If this IP is already in the blacklist, sure, kill! The second valve is called "defaul_access_valve" and it does a routine check, and if it passes, OK, passing the request to the current container's subcontainers. It is in this way that the demand is transmitted and flowed in each container, and finally arrives at the destination.
    valve: This is the valve mentioned above.
   There are probably such things in Tomcat. We can simply understand the framework of tomcat in this way. It is a top-down structure with sub-containers in the container.
2. The startup process of Tomcat
   This article is about how tomcat is started. Now that we have a general understanding of the framework structure of TOMCAT, we can guess that the startup of tomcat will start the parent container first, and then one by one. Start the subcontainer inside. When each container is started, the components installed on it will be started. When all components are started and all containers are started, tomcat itself is started.
   As a matter of course, we can also guess that the startup of tomcat will be divided into two parts, the first step is the assembly work. The second step is to start the job. 
   Assembly work is the work of placing child containers on the parent container and inserting components into each container. Here we will use the digester mode. As for what the digester mode is, what is it used for, and how it works. Please refer to <http://software.ccidnet.com/pub/article/c322_a31671_p2.html>;
   the startup work is the assembly work After that, once the assembly is successful, we just need to light the top wire and the whole tomcat will be activated.
2.1 Some interesting names:
   Catalina
   Tomcat
   Bootstrap
   Engin
   Host
   Context
   They have interesting meanings:
   Catalina: Long Range Bomber
   Tomcat: Panda Bomber 

   Bootstap: Boot
   Engin: Engine
   Host: Host, Territory
   Context: Content, Target, Context
   
2.2 The startup of tomcat is started from the class org.apache.catalina.startup.Bootstrap!
   Two things are done in Bootstrap:
   1. Three types of classloaders are specified:
      commonLoader: common/classes, common/lib, common/endorsed
      catalinaLoader: server/classes, server/lib, commonLoader
      sharedLoader: shared/classes, shared/ lib, commonLoader
   2. Boot the startup of Catalina.
      Use Reflection technology to call the process method of org.apache.catalina.startup.Catalina, and pass parameters in the past.
   
2.3 Catalina.java
   Catalina has completed several important tasks:
   1. Assemble tomcat containers and components using Digester technology.
      1.1 The main content of the assembly work is to install each large piece. For example, what kind of servcie is there under the server. How many contexts the Host will hold. Context will use which components and so on. 
      1.2 At the same time, in the assembly step, the configuration of mbeans is also completed. Here, I briefly but not very precisely describe what mbean is and what it is for.
          The objects we generate by ourselves, we manage by ourselves, are just right! But what if we create an object and want someone else to take care of it? I guess at least tell someone what we all have and how to find it! JMX technology provides us with a means. There are three main things in JMX. Mbean, agent, connector.
       Mbean: used to map our objects. Maybe the mbean is the object we created, maybe not, but with it, we can refer to our object.
       Agent: Through it, mbean can be found.
       Connector: The way to connect the Agent. It can be http, rmi, or directly through socket.
      What happens during the tomcat assembly process: The initialization of the GlobalResourcesLifecycleListener class is triggered:
         protected static Registry registry = MBeanUtils.createRegistry();
         MBeanUtils.createRegistry() is run according to /org/apache/catalina/mbeans/mbeans-descriptors. The xml configuration file creates mbeans. Ok, the outside world has a way to access the various components in tomcat. (a bit like a back door)
   2. Initialize the top level server. In fact, it is to do two connectors that are usually configured for service. (http, ajp)
   3. Start from the server container and ignite the entire tomcat.
   4. Make a hook program for the server to detect when the server shuts down and close the tomcat for each container.
   5. Listen to port 8005, and close the 8005serverSocket if it sends "SHUTDOWN" (a string built by default).
2.4 Start each container
   1. The Server
      triggers three events before the Server container starts (before_start), during the start (start), and after the start (after_start), and runs the corresponding event handler.
      Start the sub-container of the Server: Servcie.    2. Service       start the sub-container of the Service: Engin       starts the Connector    3. When Engin       reaches the level of Engin, and the containers at the following levels, Tomcat uses a relatively consistent startup method.       First, run some tasks unique to each container       . Then, trigger the pre-start event       immediately, and set the label to indicate that the container has been started.       Then, start each component in the container: loader, logger, manager, etc.       Then, start the mapping component. (Note 1) 










      Next, start the subcontainer.
      Next, start the container's pipeline (pipline)
      Then, trigger the in-start event
      and finally, trigger the post-start event.

      Engin will generally do this, Host will generally do the same, and Context will generally do the same. So obviously, we need to use the technology of code reuse here. Tomcat uses abstract classes beautifully to deal with this problem. ContainerBase. Finally, this part of the code that completes the complex functions is clean and neat.
      
      In the pre-start event of the trigger of Engin, the only Listener bound to the Engin will be activated: EnginConfig.
      This EnginConfig class basically does nothing but set the debug level of EnginConfig to be equivalent to Engin. The other is to output a few lines of text, indicating that Engin has been configured and has not done any substantive work.
      Note 1: The purpose of the mapping component is that when a requirement is to be passed from the parent container to the child container, and the parent container has multiple child containers, which child container should be selected to handle the demand? This is determined by the mapping component.    4.        Like Engin, Host also calls the start() method in ContainerBase, but it has done some own tasks before, that is, to the channel (pipline) of the host container, installed a method called "org.apache.catalina. valves.ErrorReportValve".
    



       The purpose of this valve is as follows: After the request is passed to the Host by the Engin, it will continue to be passed to the Context for specific processing. The requirement here is actually the Request, Response passed as parameters. Therefore, after the context has processed the requirements, the response is usually changed. The function of this org.apache.catalina.valves.ErrorReportValve is to check whether the response contains errors, and if so, deal with them accordingly.
   5.
       When the Context is here, it is finally the real highlight of the tomcat startup, starting the Context.
StandardContext.start() This method of starting the Context container is called by StandardHost.
5.1 webappResources The specific directory pointed to by the context
5.2 Install defaultContext, DefaultContext is the default Context. If we install DefaultContext under a Host, and a database connection pool resource is installed in defaultContext. Then all other Contexts under the Host can directly use this database connection pool without extra configuration.
  5.3 Specify Loader. Usually the default org.apache.catalina.loader.WebappLoader class is used. Loader is used to specify which classes and jar packages will be used in this context.
5.4 Specify Manager. Usually the default org.apache.catalina.session.StandardManager is used. Manager is used to manage sessions.
     In fact, session management is also very easy to achieve. Take a simple session management as an example. When the request is passed, there is a sessionId property in the Request object. OK, after getting this sessionId, we can use it as the key of the map, and we can put a HashMap in the value. Inside the HashMap, we can put what we want.
5.5 postWorkDirectory (). There is a work directory under Tomcat. We throw all temporary files there. This step is to create a directory there. Generally speaking, a directory will be generated in %CATALINA_HOME%/work/Standalone/localhost/.
5.6 Binding thread. At this point, the class Loader exchange should occur. Before, you can see all the classes and libs under tomcat. Next, you need to see the classes under the current context. So you need to set the contextClassLoader, and at the same time record the old ClassLoader, because it will be used later.
5.7 Start Loader. Specify which classes and jar files to use for this Context. If reloadable is set to true, a thread will be started to monitor changes to classes and restart the Context if there are changes.
5.8 Start the logger
5.9 Trigger a listener installed on it.
lifecycle.fireLifecycleEvent(START_EVENT, null); 
As one of the listeners, ContextConfig will be started. ContextConfig is used to configure web.xml. For example, how many Servlets and how many Filters there are in this Context, which are installed here for the Context.
5.9.1 defaultConfig. Each context has to configure the file tomcat/conf/web.xml.
5.9.2 applicationConfig configure its own WEB-INF/web.xml file
5.9.3 validateSecurityRoles permission verification. Usually when we access /admin or /manager, we need the user to be either admin or manager to access. And we can also restrict which resources are accessible and which are not. It's all done here.
5.9.4 tldScan: Scan, what tags need to be used (tag lab)
5.10 Start manager
5.11 postWelcomeFiles() The names of the three startup files we usually use:
index.html, index.htm, index.jsp Binding to this context by default
5.12 listenerStart configure listener
5.13 filterStart configure filter
5.14 Start Servlet with <load-on-startup>;1</load-on-startup>;. The
  order is from small to large: 1,2 ,3... The last is 0
  By default, at least the following 3 servlets will be started: 
  org.apache.catalina.servlets.DefaultServlet   
      handles static resource servlets. What kind of pictures, html, css, js are all found .
  org.apache.catalina.servlets.InvokerServlet
      handles those servlets without Servlet Mapping.
  org. apache.jasper.servlet.JspServlet       handles JSP files.        5.15 Identifying the context has been started. How many steps have been taken, the Context is finally started.     OK! At this point, every container and component has been started. We know the overall framework of tomcat, what components are there, and what each component is used for. I think, next we should look at how tomcat handles jsp and servlet requests. 1. Let's follow TOMCAT with a specific example to see how it delivers the Request layer by layer to the next container, and finally to the Wrapper for processing. Taking http://localhost:8080/web/login.jsp as an example (the following examples are all based on the tomcat4 source code) this experience is mainly divided into 3 parts: the early stage, the middle stage, and the final stage. Early stage: Explain how to enter a URL in the browser and how to be caught by tomcat. 




    



















Mid-term: After being caught by tomcat, how to shuttle in each container, and finally reach the final processing location.

The last stage: explain how to deal with it in detail after reaching the final processing location.

2. The birth of Request in the early stage.

    Here I will briefly talk about the request.

     Let's look at this URL first: http://localhost:8080/web/login.jsp It uses port 8080 for socket communication.

     We know that      messages can come and go through        InputStream in = socket.getInputStream() and        OutputStream out = socket.getOutputStream() .      But if the Stream is shown to the application layer, it is obviously inconvenient to operate.      Therefore, in the Connector of tomcat, the socket is encapsulated into two objects of Request and Response.      We can simply think of Request as the data sent to the server, and Response as the data that we want to send to the server.      But then there are other problems? The Request object encapsulates the socket, but it provides too many things. 



 



 





     



     Such as Request.getAuthorization(), Request.getSocket(). Things like Authorization are basically not used by developers, and things like sockets are potentially dangerous when exposed to developers. Also, the standard communication classes in the Servlet Specification are ServletRequest and HttpServletRequest, not the Request class. So, So, So. Tomcat must be able to hold the Request. Finally, tomcat chose to use the tamper mode (should be called the adapter mode) to solve this problem. It mashes org.apache.catalina.Request into org.apache.coyote.tomcat4.CoyoteRequest. And CoyoteRequest implements two interfaces, ServletRequest and HttpServletRequest. This provides the methods developers need and just need.



    Ok, let's set a breakpoint here in the invoke() method of StandardEngin's top-level container, and then visit

    http://localhost:8080/web/login.jsp, let's take a look at the places we will pass by in the early stage:

       1 .run (): 536, java.lang.Thread, Thread.java

       CurrentThread

      2. run(): 666, org.apache.tomcat.util.threads.ThreadPool$ControlRunnable, ThreadPool.java

               ThreadPool

       3. runIt(): 589, org.apache.tomcat.util.net.TcpWorkerThread, PoolTcpEndpoint.java

          ThreadWorker

4. processConnection(): 549

org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler, Http11Protocol.java

                  http protocol parser

      5 .Process(): 781, org.apache.coyote.http11.Http11Processor, Http11Processor.java

          http request processor

       6. service(): 193, org.apache.coyote.tomcat4.CoyoteAdapter,CoyoteAdapter.java

          adapter

       7. invoke() : 995, org.apache.catalina.core.ContainerBase, ContainerBase.java

   StandardEngin



    1. Main thread

    2. Start the thread pool.

    3. Call out the idle worker threads in the thread pool.

    4. Pass the data encapsulated by the httpd protocol over port 8080 and parse it into Request and Response objects.

    5. Use Http11Processor to process the request

    6. In Http11Processor, it will call CoyoteAdapter for adaptation processing, and adapt the Request to CoyoteRequest that implements the ServletRequest and HttpServletRequest interfaces.

7. At this point, the previous work of hair removal is done Basically done, can be handed over to StandardEngin to do the core processing work.



3. Medium term. Shuttle between containers.

    The shuttle of Request in each container is roughly in this way:

    each container has a pipeline (pipline), which is specially used to transmit Request.

    There are several valves in the pipeline, which are specially used to filter Request.

    A default valve is usually placed in the lower part of the pipe. The valves will do at least one thing, which is to pass the Request to the subcontainer.

    Let's imagine this:

     when a Request enters a container, it flows in a pipe, passing through various valves. On the way to the last valve, jerk~ that damn valve threw it to the subcontainer. And then start again Poro~ Poro~ Poro~ ... 嗧~.... Poro~ Poro~ Poro~ .... 嗧~....     It is in this way that Request has gone all the way container. (feels a bit like the digestive system) 



    OK, let's take a look at what containers are there, what valves are in each container, and what do these valves do to our Request:



3.1 StandardEngin's pipeline contains: StandardEnginValve

is here, VALVE does Three things:

1. Verify that the passed request is httpservletRequest.

2. Verify that the passed request carries the host header information.

3. Select the corresponding host to process it. (Generally we only have one host:localhost, which is 127.0.0.1).

At this place, our request has completed its historical mission in this part of Engin, leading to the next stop with an uncertain future: host.



3.2 The pipline of StandardHost contains: StandardHostValve

1. Verify whether the passed request is httpservletRequest.

2. Determine which Context to handle according to the Request.

Context is actually webapp, such as http://localhost:8080/web/login.jsp where web is Context Luo! 3. Now that the Context is determined, the classloader of that Context should be paid to the current thread.         Thread.currentThread().setContextClassLoader(context.getLoader().getClassLoader()); 



 



   In this way, the request can only see the classes and jars under the specified context, but not the classes of the tomcat itself, such as Engin and Valve. Otherwise, it's worth it!

4. Now that the request is here, it seems that the user is ready to access the web app, so why not update the user's session? Ok, let the manager update the user's session information

. 5. Give it to the specific Context container to continue processing the Request.

6. After the Context is processed, return the classloader.



3.3 The pipline of StandardContext contains: StandardContextValve

1. Verify whether the passed request is httpservletRequest.

2. If the request intention is not right, you want to access things in the directories /meta-inf, /web-inf, huh, useless D!

3. At this time, we will decide which Wrapper to use to process this Reqeust according to whether the Request is a servlet, a jsp, or a static resource.

4. Once you decide which Wrapper to use, OK, let that Wrapper handle it.



4. The end. How to deal with different requirements.

StandardWrapper

has not explained Wrapper before, in fact, it is such a thing.

When we process Request, it can be divided into 3 types.

Handle static: org.apache.catalina.servlets.DefaultServlet   

Handling jsp: org.apache.jasper.servlet.JspServlet handling servlet: org.apache.catalina.servlets.InvokerServlet Different requests are handled by these three different servlets. Wrapper is a simple encapsulation of them. With Wrapper, we can easily intercept every Request. You can also easily call the servlet's init() and destroy() methods, which is easy to manage! The specific situation is as follows:    if the request is to find a jsp file, the StandardWrapper will encapsulate an org.apache.jasper.servlet.JspServlet to process it.    If the request is looking for static resources, StandardWrapper will encapsulate an org.apache.jasper.servlet.DefaultServlet to process it.    If the request is looking for a servlet, StandardWrapper will encapsulate an org.apache.jasper.servlet.InvokerServlet to handle it. The StandardWrapper is also a container. Since it is a container, there must be a pipe inside for the request to wear. There must also be a valve at the lower part of the pipe (Note 1), which is used for the last interception work. In the bottom valve, in fact, It mainly does two things:    one is to start the filter and let the request pass through N filters, if OK! Then PASS. Otherwise, go elsewhere. 























   The second is servlet.service((HttpServletRequest) request,(HttpServletResponse) response); This method.

     If it is JspServlet, then first compile the jsp file into servlet_xxx, and then invoke the servlet_xxx's servie() method.

     If it is DefaultServlet, it will directly find the static resource, take out the content, and send it out.

     In the case of InvokerServlet, the service() method of that specific servlet is called.

   ok! Done.

Note 1: The valve in the StandardWrapper is the last gate. If the valve wants to pass the request to a subcontainer of StandardWrapper for processing. Sorry, Wrapper is considered as the last container in the design consideration, and there is no chance to add sub-containers to Wrapper at all! If you just want to call addChild(), throw IllegalArgumentException immediately!

 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326986860&siteId=291194637