• notice
  • Congratulations on the launch of the Sought Tech site

The main function and working principle of Tomcat servlet container Container

Tomcat's servlet container part mainly deals with servlet-related content:

  1. Load the servlet and call the service method of the servlet to process the request;

  2. Fill the response response as the content returned to the web client;

The above is the core content of the servlet container. But as a mature servlet container, Tomcat has made a more detailed architecture division, making Tomcat's servlet container more powerful and of course more complex.

  1. Container: org.apache.catalina.Container

    1. level

    2. order

  2. Context: org.apache.catalina.Context

  3. Wrapper: org.apache.catalina.Wrapper

  4. Single servlet servlet container-Wrapper only

  5. Multi-servlet servlet container-use Context

  6. Host: org.apache.catalina.Host

    1. app base & doc base

  7. Match Context and Wrapper according to uri

    1. Match Host

    2. Match servlet

    3. Servlet configuration example

  8. Servlet container with Host

  9. Engine: org.apache.catalina.Engine

  10. Servlet container with Engine

  11. File location

Container: org.apache.catalina.Container

The interface that Tomcat's servlet container must implement.

level

Container is subdivided into four roles in Tomcat, and four Container sub-interfaces are introduced:

  • Engine: The entire Catalog servlet engine;

  • Host: a virtual host containing multiple Context containers;

  • Context: a web application that contains multiple wrappers;

  • Wrapper: an independent servlet;

They are all container Containers, which are contained in layers, and the upper-level Container can have sub-Containers. Wrapper represents the most basic servlet, so it can no longer contain child containers; Engine, as the top-level Container, can no longer have parent containers . Container's addChild/removeChild/findChild methods are not applicable to Wrapper, and an exception is thrown directly.

Since a Container can contain sub-Containers, for example, a Context can contain multiple wrappers, which wrapper should be used to process a request ? The Container of Tomcat4 has a map method to obtain a sub-Container according to the content of the request, that is, use the corresponding Wrapper to process the corresponding request.

As mentioned last time, after HttpProcessor processes the http request, it will process the request. The processing method is: get the Container in the HttpConnector and call the invoke method of the Container . Therefore, the Container must have an invoke method.

In addition, Container supports a bunch of components, such as loader, logger, manager, realm, and resource. Just like the Connector is associated with the Container, the so-called "association" means that the Container contains these objects, and there are a bunch of get/set methods for these objects . Such as getLoader/setLoader.

order

When calling the servlet, Tomcat designed the Pipeline interface to ensure a series of chained calls.

The Pipeline interface has a basic valve, in addition to which many custom valves can be added.When calling the servlet, the custom valve is called first, and the basic value is called last. A valve is like a filter in a pipeline.If a valve does not allow a request to pass (such as a permission authentication valve), it ends.

Fake code:

for valve in valves:
   valve.invoke
   basicValve.invoke

So the Pipeline interface is very clear, and they are all methods associated with value and basic valve:

public interface Pipeline {
   public Valve getBasic();
   public void setBasic(Valve valve);
   public void addValve(Valve valve);
   public Valve[] getValves();
   public void invoke(Request request, Response response) throws IOException, ServletException;
   public void removeValve(Valve valve);}

Context: org.apache.catalina.Context

Context contains Wrapper, an important function is to find a suitable servlet (Wrapper) according to the request.

The addServletMapping method of Context associates a url with a servlet :

    /**
    * Add a new servlet mapping, replacing any existing mapping for
    * the specified pattern.
    *
    * @param pattern URL pattern to be mapped
    * @param name Name of the corresponding servlet to execute
    */
   public void addServletMapping(String pattern, String name);

The map method (in the parent interface Container) implements the function of searching for servlets based on requests:

    /**
    * Return the child Container that should be used to process this Request,
    * based upon its characteristics. If no such child Container can be
    * identified, return <code>null</code> instead.
    *
    * @param request Request being processed
    * @param update Update the Request to reflect the mapping selection?
    */
   public Container map(Request request, boolean update);

The search process generally relies on a Mapper, so there is also an addMapper method in the Container:

    /**
    * Add the specified Mapper associated with this Container.
    *
    * @param mapper The corresponding Mapper implementation
    *
    * @exception IllegalArgumentException if this exception is thrown by
    *  the <code>setContainer()</code> method of the Mapper
    */
   public void addMapper(Mapper mapper);

The map function is actually implemented by the map interface in Mapper:

    /**
    * Return the child Container that should be used to process this Request,
    * based upon its characteristics. If no such child Container can be
    * identified, return <code>null</code> instead.
    *
    * @param request Request being processed
    * @param update Update the Request to reflect the mapping selection?
    */
   public Container map(Request request, boolean update);

Look at the map method implemented by Mapper in a simplified version of Context:

  public Container map(Request request, boolean update) {
   // Identify the context-relative URI to be mapped
   String contextPath =
     ((HttpServletRequest) request.getRequest()).getContextPath();
   String requestURI = ((HttpRequest) request).getDecodedRequestURI();
   String relativeURI = requestURI.substring(contextPath.length());
   // Apply the standard request URI mapping rules from the specification
   Wrapper wrapper = null;
   String servletPath = relativeURI;
   String pathInfo = null;
   String name = context.findServletMapping(relativeURI);
   if (name != null)
     wrapper = (Wrapper) context.findChild(name);
   return (wrapper);
 }
  1. Get the uri of the request;

  2. According to the servlet mapping, find the servlet name corresponding to the uri;

  3. According to the servlet name, find the servlet (Wrapper);

The uri and the servlet class name correspond through the servlet name, so the uri and the servlet class name do not need to have a direct relationship, and the two are decoupled .

Wrapper: org.apache.catalina.Wrapper

Wrapper represents a servlet.The most important method to manage servlet is:

  • allocate: Instantiate a Servlet object, then you can call its service method to provide services;

Another method of Wrapper is very important:

  • setServletClass(String)Set the class name of the servlet represented by the wrapper. Then load the servlet class according to this class name and instantiate the servlet ;

Look at a simplified version of allocate implementation:

  public Servlet allocate() throws ServletException {
   // Load and initialize our instance if necessary
   if (instance==null) {
     try {
       instance = loadServlet();
     }
     catch (ServletException e) {
       throw e;
     }
     catch (Throwable e) {
       throw new ServletException("Cannot allocate a servlet instance", e);
     }
   }
   return instance;
 }
 private Servlet loadServlet() throws ServletException {
   if (instance!=null)
     return instance;
   Servlet servlet = null;
   String actualClass = servletClass;
   if (actualClass == null) {
     throw new ServletException("servlet class has not been specified");
   }
   Loader loader = getLoader();
   // Acquire an instance of the class loader to be used
   if (loader==null) {
     throw new ServletException("No loader.");
   }
   ClassLoader classLoader = loader.getClassLoader();
   // Load the specified servlet class from the appropriate class loader
   Class classClass = null;
   try {
     if (classLoader!=null) {
       classClass = classLoader.loadClass(actualClass);
     }
   }
   catch (ClassNotFoundException e) {
     throw new ServletException("Servlet class not found");
   }
   // Instantiate and initialize an instance of the servlet class itself
   try {
     servlet = (Servlet) classClass.newInstance();
   }
   catch (Throwable e) {
     throw new ServletException("Failed to instantiate servlet");
   }
   // Call the initialization method of this servlet
   try {
     servlet.init(null);
   }
   catch (Throwable f) {
     throw new ServletException("Failed initialize servlet.");
   }
   return servlet;
 }

According to the class name of the servlet, load and instantiate the servlet, and then call the init of the servlet to initialize the servlet.

Single servlet servlet container-Wrapper only

The server starts the connector and associates the connector with the wrapper at the same time. The wrapper adds two simple valves to do some header and ip related things:

public final class Bootstrap1 {
 public static void main(String[] args) {/* call by using http://localhost:8080/ModernServlet,
  but could be invoked by any name */
   HttpConnector connector = new HttpConnector();
   Wrapper wrapper = new SimpleWrapper();
   wrapper.setServletClass("ModernServlet");
   Loader loader = new SimpleLoader();
   Valve valve1 = new HeaderLoggerValve();
   Valve valve2 = new ClientIPLoggerValve();
   wrapper.setLoader(loader);
   ((Pipeline) wrapper).addValve(valve1);
   ((Pipeline) wrapper).addValve(valve2);
   connector.setContainer(wrapper);
   try {
     connector.initialize();
     connector.start();
     // make the application wait until we press a key.
     System.in.read();
   }
   catch (Exception e) {
     e.printStackTrace();
   }
 }}

Using System.in.read()block main thread is really a programming genius! Should be used normally Thread#join, let the main thread wait.

Wrapper contains a pipeline, adding a valve is adding to the pipeline. So where is the basic valve?

  public SimpleWrapper() {
   pipeline.setBasic(new SimpleWrapperValve());
 }

When creating a SimpleWrapper instance, it will directly create a SimpleWrapperValve as a basic valve.

As a container, wrapper uses a pipeline to process request/response in its invoke implementation:

  public void invoke(Request request, Response response)
   throws IOException, ServletException {
   pipeline.invoke(request, response);
 }

The pipeline's invoke implementation is like the pseudo code above, calling each valve in turn, and finally calling the basic valve.

The basic valve is responsible for loading the servlet and calling the service method , so its invoke is implemented as:

  public void invoke(Request request, Response response, ValveContext valveContext)
   throws IOException, ServletException {
   SimpleWrapper wrapper = (SimpleWrapper) getContainer();
   ServletRequest sreq = request.getRequest();
   ServletResponse sres = response.getResponse();
   Servlet servlet = null;
   HttpServletRequest hreq = null;
   if (sreq instanceof HttpServletRequest)
     hreq = (HttpServletRequest) sreq;
   HttpServletResponse hres = null;
   if (sres instanceof HttpServletResponse)
     hres = (HttpServletResponse) sres;
   // Allocate a servlet instance to process this request
   try {
     servlet = wrapper.allocate();
     if (hres!=null && hreq!=null) {
       servlet.service(hreq, hres);
     }
     else {
       servlet.service(sreq, sres);
     }
   }
   catch (ServletException e) {
   }
 }

As mentioned before, the allocate of Wrapper is responsible for instantiating a servlet , so the basic valve is called to Wrapper#allocateobtain a servlet, and then call the service method.

Multi-servlet servlet container-use Context

Compared with a servlet container with only one servlet, multiple servlets are a more common scenario.Context needs to be used to manage multiple wrappers:

public final class Bootstrap2 {
 public static void main(String[] args) {
   HttpConnector connector = new HttpConnector();
   Wrapper wrapper1 = new SimpleWrapper();
   wrapper1.setName("Primitive");
   wrapper1.setServletClass("PrimitiveServlet");
   Wrapper wrapper2 = new SimpleWrapper();
   wrapper2.setName("Modern");
   wrapper2.setServletClass("ModernServlet");
   Context context = new SimpleContext();
   context.addChild(wrapper1);
   context.addChild(wrapper2);
   Valve valve1 = new HeaderLoggerValve();
   Valve valve2 = new ClientIPLoggerValve();
   ((Pipeline) context).addValve(valve1);
   ((Pipeline) context).addValve(valve2);
   Mapper mapper = new SimpleContextMapper();
   mapper.setProtocol("http");
   context.addMapper(mapper);
   Loader loader = new SimpleLoader();
   context.setLoader(loader);
   // context.addServletMapping(pattern, name);
   context.addServletMapping("/Primitive", "Primitive");
   context.addServletMapping("/Modern", "Modern");
   connector.setContainer(context);
   try {
     connector.initialize();
     connector.start();
     // make the application wait until we press a key.
     System.in.read();
   }
   catch (Exception e) {
     e.printStackTrace();
   }
 }}

At this time, the container associated with the connector is the Context.

Compared with a single servlet, the biggest change is undoubtedly the mapper : the mapping between url and servlet name. This mapping is managed by Context, such as associating "/Primitive" with a servlet named "Primitive" (wrapper1), and its servlet class is "PrimitiveServlet".

The invoke of Context is also implemented by its pipeline. Its basic valve is only responsible for finding the Wrapper, and the Wrapper will handle the things that the Wrapper has to do :

  public void invoke(Request request, Response response, ValveContext valveContext)
   throws IOException, ServletException {
   // Validate the request and response object types
   if (!(request.getRequest() instanceof HttpServletRequest) ||
     !(response.getResponse() instanceof HttpServletResponse)) {
     return;     // NOTE - Not much else we can do generically
   }
   // Disallow any direct access to resources under WEB-INF or META-INF
   HttpServletRequest hreq = (HttpServletRequest) request.getRequest();
   String contextPath = hreq.getContextPath();
   String requestURI = ((HttpRequest) request).getDecodedRequestURI();
   String relativeURI =
     requestURI.substring(contextPath.length()).toUpperCase();
   Context context = (Context) getContainer();
   // Select the Wrapper to be used for this Request
   Wrapper wrapper = null;
   try {
     wrapper = (Wrapper) context.map(request, true);
   }
   catch (IllegalArgumentException e) {
     badRequest(requestURI, (HttpServletResponse) response.getResponse());
     return;
   }
   if (wrapper == null) {
     notFound(requestURI, (HttpServletResponse) response.getResponse());
     return;
   }
   // Ask this Wrapper to process this Request
   response.setContext(context);
   wrapper.invoke(request, response);
 }

So Tomcat shows the benefits of container layering:

  • Context finds the Wrapper corresponding to the request through the basic valve of its own pipeline;

  • Wrapper loads the servlet and provides services through the basic valve of its own pipeline;

流程:Context -> Context’s pipeline -> Context’s basic valve -> find Wrapper -> Wrapper’s pipeline -> Wrapper’s basic valve -> init servlet, service

Tomcat's parent and child components have pointers to each other, so it feels like a tree.

Host: org.apache.catalina.Host

And Context is almost a mirrored process.

app base & doc base

Context can be setDocBaseused as the context path of the web application, and Host can be setAppBaseused as the root path of the application.

These paths specify where to load the application.

In the official Tomcat deployment, the app base defaults to webapps, and the doc base of the context is the name of the folder where the application is located. These are all configured in Tomcat conf/server.xml. The app is written by the programmer himself, and the configuration is also determined by the programmer.The general configuration is in webapps/<app>/WEB-INF/web.xml.

Match Context and Wrapper according to uri

Host looks for Context, Context looks for Wrapper, both are based on uri.

Match Host

Context has a setPath, the actual implementation is to set the name setName for the Context. Because when Host matches Context according to uri, it matches the names of uri and Context .

For details, see the StandardHostMapper#mapcall when matching StandardHost#map:

        Context context = null;
       String mapuri = uri;
       while (true) {
           context = (Context) findChild(mapuri);
           if (context != null)
               break;
           int slash = mapuri.lastIndexOf('/');
           if (slash < 0)
               break;
           mapuri = mapuri.substring(0, slash);
       }
       // If no Context matches, select the default Context
       if (context == null) {
           if (debug > 1)
               log("  Trying the default context");
           context = (Context) findChild("");
       }
       // Complain if no Context has been selected
       if (context == null) {
           log(sm.getString("standardHost.mappingError", uri));
           return (null);
       }
  1. First match the entire uri with the name of the Context to see if you can find the Context;

  2. If it is not found, remove the part after the current last slash, continue to match, and continue to delete if it is not found, until the uri is deleted or found;

  3. Return Context if it is found, return the default Context (Context with an empty name) if it is not found, and return null if there is no default;

For example, for a a/b/c/hellorequest, hello is used as the servlet name to match Wrapper in the Context a/b/cto match the Context. Use a/bit aif it is not matched, use it if it is not matched, and see if there is an empty ""Context.

However, suppose the Context is named a, the Wrapper is named hello, and a request uri is a/b/c/hello, it can match the default Context, but it cannot match the Wrapper , because the Context path is removed from the uri, aand the rest is b/c/helloused for servlet matching . The specific implementation is divided into two parts:

First, after the Host matches the Context for the Request, it will associate the Request with the Context and set the path of the Context to the Request . See details StandardHostMapper#map:

        // Perform mapping on our request URI
       String uri = ((HttpRequest) request).getDecodedRequestURI();
       Context context = host.map(uri);
       // Update the request (if requested) and return the selected Context
       if (update) {
           request.setContext(context);
           if (context != null)
               ((HttpRequest) request).setContextPath(context.getPath());
           else
               ((HttpRequest) request).setContextPath(null);
       }
       return (context);

Match servlet

The second part is realized when matching Wrapper.

Matching the servlet means that the entire uriContext#addServletMapping is matched with the mapping of the Wrapper after the context path is removed (by adding), and after the mapping is found, the Wrapper name corresponding to the mapping is found . See details StandardContextMapper#map:

    public Container map(Request request, boolean update) {
       int debug = context.getDebug();
       // Has this request already been mapped?
       if (update && (request.getWrapper() != null))
           return (request.getWrapper());
       // Identify the context-relative URI to be mapped
       String contextPath =
           ((HttpServletRequest) request.getRequest()).getContextPath();
       String requestURI = ((HttpRequest) request).getDecodedRequestURI();
       String relativeURI = requestURI.substring(contextPath.length());
       if (debug >= 1)
           context.log("Mapping contextPath='" + contextPath +
                       "' with requestURI='" + requestURI +
                       "' and relativeURI='" + relativeURI + "'");
       // Apply the standard request URI mapping rules from the specification
       Wrapper wrapper = null;
       String servletPath = relativeURI;
       String pathInfo = null;
       String name = null;
       // Rule 1 -- Exact Match
       if (wrapper == null) {
           if (debug >= 2)
               context.log("  Trying exact match");
           if (!(relativeURI.equals("/")))
               name = context.findServletMapping(relativeURI);
           if (name != null)
               wrapper = (Wrapper) context.findChild(name);
           if (wrapper != null) {
               servletPath = relativeURI;
               pathInfo = null;
           }
       }
       // Rule 2 -- Prefix Match
       if (wrapper == null) {
           if (debug >= 2)
               context.log("  Trying prefix match");
           servletPath = relativeURI;
           while (true) {
               name = context.findServletMapping(servletPath + "/*");
               if (name != null)
                   wrapper = (Wrapper) context.findChild(name);
               if (wrapper != null) {
                   pathInfo = relativeURI.substring(servletPath.length());
                   if (pathInfo.length() == 0)
                       pathInfo = null;
                   break;
               }
               int slash = servletPath.lastIndexOf('/');
               if (slash < 0)
                   break;
               servletPath = servletPath.substring(0, slash);
           }
       }
       // Rule 3 -- Extension Match
       if (wrapper == null) {
           if (debug >= 2)
               context.log("  Trying extension match");
           int slash = relativeURI.lastIndexOf('/');
           if (slash >= 0) {
               String last = relativeURI.substring(slash);
               int period = last.lastIndexOf('.');
               if (period >= 0) {
                   String pattern = "*" + last.substring(period);
                   name = context.findServletMapping(pattern);
                   if (name != null)
                       wrapper = (Wrapper) context.findChild(name);
                   if (wrapper != null) {
                       servletPath = relativeURI;
                       pathInfo = null;
                   }
               }
           }
       }
       // Rule 4 -- Default Match
       if (wrapper == null) {
           if (debug >= 2)
               context.log("  Trying default match");
           name = context.findServletMapping("/");
           if (name != null)
               wrapper = (Wrapper) context.findChild(name);
           if (wrapper != null) {
               servletPath = relativeURI;
               pathInfo = null;
           }
       }
       // Update the Request (if requested) and return this Wrapper
       if ((debug >= 1) && (wrapper != null))
           context.log(" Mapped to servlet '" + wrapper.getName() +
                       "' with servlet path '" + servletPath +
                       "' and path info '" + pathInfo +
                       "' and update=" + update);
       if (update) {
           request.setWrapper(wrapper);
           ((HttpRequest) request).setServletPath(servletPath);
           ((HttpRequest) request).setPathInfo(pathInfo);
       }
       return (wrapper);
   }
  1. First, after removing the context path from the url, the rest is used to match the servlet;

  2. Match directly first;

  3. Again, like Host matching Context, use prefix path matching, that is, throw the content after the last slash;

  4. Then expand the match, expand the name to match, for example *.jsp;

  5. Finally, the default matching is /the servlet whose mapping is ;

  6. Binding the servlet and request when found, after all, the matching process is quite troublesome;

So for matching servlet, exact match> prefix path match> extension match> default servlet .

The matching is to match the mapping, and then find the name of the Wrapper according to the mapping.

When matching, the query string will not be treated as part of the uri.

Host matches Context using url to find Context name, which is the path of Context. Context matching Wrapper uses the mapping of url to find Context, and then finds Wrapper name according to the mapping.

Servlet configuration example

It is only the matching setting of Wrapper and uri in Context, and has nothing to do with Host matching Context.

Exact match:

<servlet-mapping>
   <servlet-name>MyServlet</servlet-name>
   <url-pattern>/puppy/detail.html</url-pattern>
   <url-pattern>/demo.html</url-pattern>
   <url-pattern>/table</url-pattern></servlet-mapping>

Path matching

<servlet-mapping>
   <servlet-name>MyServlet</servlet-name>
   <url-pattern>/user/*</url-pattern></servlet-mapping>

Suffix match:

<servlet-mapping>
   <servlet-name>MyServlet</servlet-name>
   <url-pattern>*.jsp</url-pattern>
   <url-pattern>*.action</url-pattern></servlet-mapping>

Servlet container with Host

    Wrapper wrapper1 = new StandardWrapper();
   wrapper1.setName("Primitive");
   wrapper1.setServletClass("PrimitiveServlet");
   Wrapper wrapper2 = new StandardWrapper();
   wrapper2.setName("Modern");
   wrapper2.setServletClass("ModernServlet");
   Context context = new StandardContext();
   // StandardContext's start method adds a default mapper
   context.setPath("/app1");
   context.setDocBase("app1");
   context.addChild(wrapper1);
   context.addChild(wrapper2);
   Host host = new StandardHost();
   host.addChild(context);
   host.setName("localhost");
   host.setAppBase("webapps");
   
   context.addServletMapping("/Primitive", "Primitive");
   context.addServletMapping("/Modern", "Modern");

At this time, all web apps webappsare loaded from below, the path of the context (app) is webapps/app1, web.xml should be there webapps/app1/WEB-INF/web.xml, servlet should be there webapps/app1/WEB-INF/classes, and lib should be there webapps/app1/WEB-INF/lib.

There is a map method in the Context interface.Find the name of the corresponding Wrapper according to the uri, and then find the Wrapper by name. The Host interface also has a map method, which also finds the name of the corresponding Context according to the uri, and finally finds the Context through the name. However, there are two differences:

  1. Context#setPathWill set name to the same value at the same time, such as /app1;

  2. Host cannot find the name of the Context according to the uri, and will throw away the content after the last slash, and continue to look for it until the Context is found or the uri is thrown out.

Just start the connector and host at startup:

    connector.setContainer(host);
   connector.initialize();
   ((Lifecycle) connector).start();
   ((Lifecycle) host).start();

Engine: org.apache.catalina.Engine

Engine contains one or more Hosts. So Engine also has the process of finding Host.

Engine matching Host has nothing to do with uri, and the serverName of request is used.

There javax.servlet.ServletRequestis a String getServerName()method in it.

Engine matches Host by matching server name and host name.

In fact, the container mapper of each level uses the findChildmethod of the Container itself, and the method of each Container uses ContainerBase#findChildthis default implementation, so when findingChild is matched with the name of the Container. The reason why Context uses mapping to find Wrapper is actually to add a layer of mapping before findChild. After actually finding the mapping, use findChild to find the Wrapper corresponding to the mapping.

Engine also has a default matching server, which is generally set to localhost. Reference StandardEngineMapper#mapimplementation:

    public Container map(Request request, boolean update) {
       int debug = engine.getDebug();
       // Extract the requested server name
       String server = request.getRequest().getServerName();
       if (server == null) {
           server = engine.getDefaultHost();
           if (update)
               request.setServerName(server);
       }
       if (server == null)
           return (null);
       server = server.toLowerCase();
       if (debug >= 1)
           engine.log("Mapping server name '" + server + "'");
       // Find the matching child Host directly
       if (debug >= 2)
           engine.log(" Trying a direct match");
       Host host = (Host) engine.findChild(server);
       // Find a matching Host by alias. FIXME - Optimize this!
       if (host == null) {
           if (debug >= 2)
               engine.log(" Trying an alias match");
           Container children[] = engine.findChildren();
           for (int i = 0; i < children.length; i++) {
               String aliases[] = ((Host) children[i]).findAliases();
               for (int j = 0; j < aliases.length; j++) {
                   if (server.equals(aliases[j])) {
                       host = (Host) children[i];
                       break;
                   }
               }
               if (host != null)
                   break;
           }
       }
       // Trying the "default" host if any
       if (host == null) {
           if (debug >= 2)
               engine.log(" Trying the default host");
           host = (Host) engine.findChild(engine.getDefaultHost());
       }
       // Update the Request if requested, and return the selected Host
       ;       // No update to the Request is required
       return (host);
   }
  1. If the request does not have a server name, set it to the address of the default host, and it must at least match the default host;

  2. If the request has a server name, see which host name matches the server name;

  3. For those requests with a server name but no host, try to see if their server name is the alias of which host. Because the alias inversion is not set, it is necessary to traverse all host queries;

  4. Haven't found the host yet? Come on, just use the default host.

Servlet container with Engine

Start the connector and engine at startup:

    Host host = new StandardHost();
   host.addChild(context);
   host.setName("localhost");
   host.setAppBase("webapps");
   
   Engine engine = new StandardEngine();
   engine.addChild(host);
   engine.setDefaultHost("localhost");
   connector.setContainer(engine);
   connector.initialize();
   ((Lifecycle) connector).start();
   ((Lifecycle) engine).start();

Here, the default Host address of Engine is set to localhost, and the name of the only Host is set to localhost. So this Host is the default host.

File location

In addition to setPath, Context also has a setDocBase. Host has an appBase and Engine has an engineBase.

These three bases have nothing to do with path. Path refers to the mapping relationship between uri and components. The base is talking about the location of the file:

  • The engine base defaults to catalina.base, and the latter defaults tocatalina.home ;

  • The app base defaults to webapps;

  • The doc base defaults to the path of the Context, which is the folder where the Context is located, or the name of the war package ;

Tomcat loads classes, resources, etc., to<engine base>/<app base>/<doc base> determine the location of resources according to the hierarchy .


Tags

Technical otaku

Sought technology together

Related Topic

1 Comments

author

lipitor 20mg pill & lt;a href="https://lipiws.top/"& gt;order lipitor 20mg sale& lt;/a& gt; atorvastatin 40mg canada

Gvsokv

2024-03-08

Leave a Reply

+