The source analysis of Tomcat's Url-pattern

Source: Internet
Author: User

1 processing of static files foreword analysis

Have you recently tried to figure out Springmvc's handling strategy for static resources, such as what is the difference between it and a normal request?

Some might say that there are some static resources that are not given to these frameworks for processing, but are delivered directly to the container, which is more efficient. What I'm trying to say is that, although this is the case, dealing with static resources is the function that the MVC framework should provide, rather than relying on the outside world.

Here is an example of the SPRINGMVC project in the Tomcat container. Access to the entire static resource, as follows:

Can be divided into the following 2 large processes

    • The process by which Tomcat chooses the servlet based on Url-pattern
    • SPRINGMVC the process of static resources (this is left to the next article to detailed source code description)
2 Tomcat's processing strategy

Here to see the source of Tomcat, so the pom to add the corresponding dependency, so that when the debug can locate the source file, currently I use the Tomcat version is 7.0.55, if you use different versions, then change the corresponding dependent version of the line

<dependency>    <groupId>org.apache.tomcat</groupId>    <artifactId>tomcat-catalina</artifactId>    <version>7.0.55</version>    <scope>provided</scope></dependency><dependency>    <groupId>org.apache.tomcat</groupId>    <artifactId>tomcat-coyote</artifactId>    <version>7.0.55</version>    <scope>provided</scope></dependency><dependency>    <groupId>org.apache.tomcat</groupId>    <artifactId>tomcat-jasper</artifactId>    <version>7.0.55</version>    <scope>provided</scope></dependency>
2.1 Tomcat Default-registered Servlet

Tomcat is registered by default, mapping the Defaultservlet of the '/' path, mapping . JSP and . Jspx Jspservlet, which are configured in the Tomcat Conf/web.xml file as follows:

<servlet>    <servlet-name>default</servlet-name>    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class></servlet><servlet>    <servlet-name>jsp</servlet-name>    <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class></servlet><servlet-mapping>    <servlet-name>default</servlet-name>    <url-pattern>/</url-pattern></servlet-mapping><servlet-mapping>    <servlet-name>jsp</servlet-name>    <url-pattern>*.jsp</url-pattern>    <url-pattern>*.jspx</url-pattern></servlet-mapping>
    • Defaultservlet can be used to process tomcat some resource files
    • Jspservlet is used to process some JSP files, some translation of these JSP files

We can modify this configuration file to add or remove some of the default servlet configurations.

Here's what the Url-pattern rules of these servlets look like.

Rules of the Url-pattern of the 2.2 servlet

For the servlet Url-pattern rules, there is also a corresponding source analysis article Tomcat Url-pattern source code analysis.

Several concepts in the 2.2.1 Tomcat source code

Before the analysis, simply look at several concepts in Tomcat source, context, Wrapper, Servlet:

    • The Servlet is very clear, that is, inherit the HttpServlet, the user uses its service method to process the request

    • Wrapper is a combination of servlets and mappings, specifically the servlet information that is configured in Web. xml

      <servlet>    <servlet-name>mvc</servlet-name>    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>    <load-on-startup>1</load-on-startup></servlet><servlet-mapping>    <servlet-name>mvc</servlet-name>    <url-pattern>/*</url-pattern></servlet-mapping>
    • The Context represents an application that contains all the information configured in Web. XML, so when a request arrives, it is responsible for locating the servlet and then invoking the Servlet's service method to execute the business logic we wrote.

The context of the above map-based search servlet package to a Org.apache.tomcat.util.http.mapper.Mapper class to complete, so the request matching rules are in this mapper to complete.

So this mapper did 2 things.

    • When initializing Web. XML, mapper needs to collect the servlet and its mapping information and handle it, storing it in Mapper's internal class Contextversion

    • When the request arrives, it can select the corresponding servlet and other information according to the request address, for use

The mapper internal class Contextversion stores the servlet corresponding to the mappings as follows:

protected static final class ContextVersion extends MapElement {    public String[] welcomeResources = new String[0];    public Wrapper defaultWrapper = null;    public Wrapper[] exactWrappers = new Wrapper[0];    public Wrapper[] wildcardWrappers = new Wrapper[0];    public Wrapper[] extensionWrappers = new Wrapper[0];    //略}

The total is divided into 5 kinds, namely

    • The Welcomeresources Welcome page, which is what you can configure in Web. XML, will be described in detail as a case study

      <welcome-file-list>    <welcome-file>index.html</welcome-file>    <welcome-file>index.htm</welcome-file></welcome-file-list>
    • Defaultwrapper for storing the default servlet information

    • Exactwrappers for exact matching, i.e. the requirements must be identical

    • Wildcardwrappers for wildcard matching such as/*,/abc/*

    • Extensionwrappers is used for extension matching, i.e. . JSP,. HTML, etc.

Let's take a look at how mapper is classified.

2.2.2 Mapper collation processing servlet and mapping information
protected void Addwrapper (contextversion context, String path, Object Wrapper, Boolean Jspwildcard, Boolean RESOURC Eonly) {synchronized (context) {if (Path.endswith ("/*")) {//Wildcard wrapper String NA            me = path.substring (0, Path.length ()-2);            Wrapper newwrapper = new Wrapper (name, Wrapper, Jspwildcard, resourceonly);            wrapper[] Oldwrappers = context.wildcardwrappers;            wrapper[] Newwrappers = new Wrapper[oldwrappers.length + 1];                if (Insertmap (Oldwrappers, Newwrappers, Newwrapper)) {context.wildcardwrappers = newwrappers;                int slashcount = Slashcount (newwrapper.name);                if (Slashcount > context.nesting) {context.nesting = Slashcount; }}} and Else if (Path.startswith ("*."))            {//Extension wrapper String name = Path.substring (2); Wrapper NewwraPper = new Wrapper (name, Wrapper, Jspwildcard, resourceonly);            wrapper[] Oldwrappers = context.extensionwrappers;            wrapper[] Newwrappers = new Wrapper[oldwrappers.length + 1];            if (Insertmap (Oldwrappers, Newwrappers, Newwrapper)) {context.extensionwrappers = newwrappers; }} else if (Path.equals ("/")) {//Default wrapper wrapper newwrapper = new Wrapper ("", WRA            Pper, Jspwildcard, resourceonly);        Context.defaultwrapper = Newwrapper;            } else {//Exact wrapper final String name; if (path.length () = = 0) {//special case for the Context Root mapping which is//treated a            s an exact match name = "/";            } else {name = path; } Wrapper newwrapper = new Wrapper (name, Wrapper, Jspwildcard, resourceonly);            wrapper[] Oldwrappers = context.exactwrappers;            wrapper[] Newwrappers = new Wrapper[oldwrappers.length + 1];            if (Insertmap (Oldwrappers, Newwrappers, Newwrapper)) {context.exactwrappers = newwrappers; }        }    }}

The above-mentioned if else statements are explained very clearly

    • The wildcard matches are included in the wildcardwrappers of the contextversion, ending with/*

    • Start with *., all included in the extension match, stored in the contextversion extensionwrappers

    • /, as default, is stored in the defaultwrapper of Contextversion

    • All the others, as exact matches, are stored in the Contextversion exactwrappers.

At this point, we may think that the URL in a variety of forms, it is not just these kinds of it. such as/a/*.jsp, that is, not with/* end, nor with *. At first, it seems that it can only be assigned to the exact match, which is not very reasonable. In fact, Tomcat restricts the URL form to death, and it checks accordingly, as follows

private boolean validateURLPattern(String urlPattern) {    if (urlPattern == null)        return (false);    if (urlPattern.indexOf(‘\n‘) >= 0 || urlPattern.indexOf(‘\r‘) >= 0) {        return (false);    }    if (urlPattern.equals("")) {        return true;    }    if (urlPattern.startsWith("*.")) {        if (urlPattern.indexOf(‘/‘) < 0) {            checkUnusualURLPattern(urlPattern);            return (true);        } else            return (false);    }    if ( (urlPattern.startsWith("/")) &&            (urlPattern.indexOf("*.") < 0)) {        checkUnusualURLPattern(urlPattern);        return (true);    } else        return (false);}

Obviously, Urlpattern can be "", others must be in *. or/start, and both cannot exist at the same time. /A/*.JSP does not meet the last condition, direct error, Tomcat failed to start, so we do not have to worry too much about the complexity of the url-pattern in the servlet tag.

Once the initialization collation is complete, when the request arrives, it needs to match the sorted data to find the appropriate servlet to respond to

2.2.3 Mapper match request corresponding servlet

In the Internalmapwrapper method of Mapper, there is a matching rule, as follows

Private final void Internalmapwrapper (contextversion contextversion, Charchunk Path,    Mappingdata mappingdata) throws Exception {//slightly//Rule 1--Exact Match    wrapper[] Exactwrappers = contextversion.exactwrappers;    Internalmapexactwrapper (exactwrappers, Path, mappingdata);    Rule 2--Prefix Match Boolean checkjspwelcomefiles = false;    wrapper[] Wildcardwrappers = contextversion.wildcardwrappers;                                   if (Mappingdata.wrapper = = null) {Internalmapwildcardwrapper (wildcardwrappers, contextversion.nesting,        Path, mappingdata);    bit}/////Rule 3--Extension Match wrapper[] extensionwrappers = contextversion.extensionwrappers; if (Mappingdata.wrapper = = null &&!checkjspwelcomefiles) {internalmapextensionwrapper (extensionwrappers,    Path, Mappingdata, true); }//Rule 4--Welcome Resources Processing for Servlets if (mappingdata.wrapper = = = null) {Boolean checkwelcomefiles = Checkjspwelcomefiles;        bit}/////Rule 7--Default servlet if (mappingdata.wrapper = = null &&!checkjspwelcomefiles) {            if (contextversion.defaultwrapper! = null) {mappingdata.wrapper = ContextVersion.defaultWrapper.object;            MappingData.requestPath.setChars (Path.getbuffer (), Path.getstart (), path.getlength ());        MappingData.wrapperPath.setChars (Path.getbuffer (), Path.getstart (), path.getlength ()); }//slightly}//slightly}

Long matching rules, interested can go to the careful study, for the welcome resources matching, the following will give 2 examples to analyze their rules in detail, the other we just understand the approximate matching order is possible, the matching sequence is as follows:

    • (1) First precision matching

    • (2) then a wildcard match

    • (3) then the extension matches

    • (4) Then the Welcome page match (here again a lot of rules are broken down, the following case analysis will be explained in detail)

    • (5) Finally, the default match

3 Case study (combined with source code)

Before you explain the case, you need to make the Tomcat information in eclipse clear, and sometimes modifying the Tomcat configuration doesn't work because the place you're modifying is not causing the

3.1 Premise: Configuration information for Tomcat in eclipse
    • The new Tomcat server, which replicates the configuration of your installed Tomcat, resides under the server project of the current Eclipse workspace path, as follows:

So in the future to modify the Tomcat information used, directly under the project to modify, or directly to the project path, directly modify the corresponding configuration file

    • The new Tomcat server is not running under the WebApps directory of the Tomcat you installed, but is under the. metadata file for the current Eclipse workspace, as follows:. metadata\.plugins\ Org.eclipse.wst.server.core, there will be one or more TMP directories in this directory, each TMP directory corresponds to a tomcat's real running environment, and then find the TMP directory you use, you will see the following information

The Wtwebapps here is the Tomcat default publishing root directory, which is not fixed, configurable.

3.2 JSP Access case

A simple example: There is a a.jsp file under the root path of Tomcat, which is the root directory of the above Tomcat release, in which we put a JSP file with the following file contents:

<%@page contentType="text/html"%><%@page pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   "http://www.w3.org/TR/html4/loose.dtd">

By default, Jspservlet exists, access HTTP://LOCALHOST:8080/A.JSP?NAME=LG, the results are as follows:

If you modify the default configuration of Tomcat and remove Jspservlet, the same access to HTTP://LOCALHOST:8080/A.JSP?NAME=LG, the results are as follows

At this point, without the jspservlet, do not do the corresponding translation work, but use Defaultservlet directly to return the contents of the file.

Because Tomcat is configured by default, maps/Defaultservlet and maps *.jsp Jspservlet. When initializing Web. XML, the Mapper class described above follows the collation rules, Defaultservlet as the default Servlet,jspservlet as the servlet with the extension, which is higher than the defaultservlet level, performs an extension match, so returns the The content of the translated JSP. When the Jspservlet is removed, the defaultservlet is used, the default match is performed, and the JSP file is simply a generic resource file, returning the original content of the JSP.

3.3 Welcome-file-list Case

It has two functions, as the main page of the project and as a jump ladder, the following first introduced two cases, and then based on the source analysis of its reasons.

Note: I use the project's root directory as a directory for Tomcat publishing, so access to http://localhost:8080/no longer joins the project name

3.3.1 as the homepage of the project
  • Case 1: Under the root path of the project, place a a.html file, Firstservlet intercept/first/, Secondservlet intercept . Action,web.xml is the following configuration

    <servlet>    <servlet-name>first</servlet-name>    <servlet-class>com.lg.servlet.FirstServlet</servlet-class>    <load-on-startup>1</load-on-startup></servlet><servlet-mapping>    <servlet-name>first</servlet-name>    <url-pattern>/first/*</url-pattern></servlet-mapping><servlet>    <servlet-name>second</servlet-name>    <servlet-class>com.lg.servlet.SecondServlet</servlet-class>    <load-on-startup>1</load-on-startup></servlet><servlet-mapping>    <servlet-name>second</servlet-name>    <url-pattern>*.action</url-pattern></servlet-mapping>  <welcome-file-list>    <welcome-file>a.html</welcome-file></welcome-file-list>

    At this point, we visit http://localhost:8080/to access the project's home page, you can access the content of a.html, as follows:

  • Case 2: Slightly modify the welcome-file-list, the other unchanged, as follows

    <welcome-file-list>    <welcome-file>a.jsp</welcome-file></welcome-file-list>

    In the root directory, store a a.jsp file as follows:

    <%@page contentType="text/html"%><%@page pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   "http://www.w3.org/TR/html4/loose.dtd">

    The access http://localhost:8080/results are returned

    It can be concluded that Tomcat uses the appropriate servlet to parse the file according to the different extensions, and then returns

3.3.2 as a jumping ladder
    • Case 3: Modify the Welcome-file-list again as follows, other unchanged:

      <welcome-file-list>    <welcome-file>a.action</welcome-file></welcome-file-list>

      There are 2 cases here, that is, whether there is a a.action in the root directory, but in either case, access to http://localhost:8080/, in this case, will return the contents of the Secondservlet configured above (but their execution logic is not the same) , the return content is as follows:

    • Case 4: Similarly, modify Welcome-file-list as follows, access http://localhost:8080/to access the contents of the Firstservlet configured above:

      <welcome-file-list>    <welcome-file>first/abc</welcome-file></welcome-file-list>
3.3.3 Source Interpretation

Below we will be based on the analysis of the source code to analyze the entire process, this part of the detailed source code is as follows:

Rule 4--Welcome resources processing for servletsif (Mappingdata.wrapper = = null) {Boolean checkwelcomefiles = ch    Eckjspwelcomefiles;        if (!checkwelcomefiles) {char[] buf = Path.getbuffer ();    Checkwelcomefiles = (Buf[pathend-1] = = '/'); } if (Checkwelcomefiles) {for (int i = 0; (I < ContextVersion.welcomeResources.length) && (mappingdata.wrapper = = null);            i++) {path.setoffset (pathoffset);            Path.setend (Pathend);            Path.append (Contextversion.welcomeresources[i], 0, Contextversion.welcomeresources[i].length ());            Path.setoffset (Servletpath); Rule 4a--Welcome resources processing for exact macth internalmapexactwrapper (exactwrappers, PATH, mapping            Data); Rule 4b--Welcome resources processing for prefix match if (mappingdata.wrapper = = null) {i Nternalmapwildcardwrapper (WildcardwrAppers, contextversion.nesting, Path, mappingdata); }//Rule 4c--Welcome resources processing//For physical folder if (Mappin                Gdata.wrapper = = NULL && contextversion.resources! = null) {Object file = null;                String pathstr = path.tostring ();                try {file = ContextVersion.resources.lookup (PATHSTR);                } catch (Namingexception NEX) {//Swallow not found, since this is normal} if (file! = NULL &&!) (                                                File instanceof DirContext) {internalmapextensionwrapper (extensionwrappers, Path,                    Mappingdata, True);                        if (Mappingdata.wrapper = = NULL && Contextversion.defaultwrapper! = null) {                           Mappingdata.wrapper = ContextVersion.defaultWrapper.object;                             MappingData.requestPath.setChars (Path.getbuffer (), Path.getstart (),                        Path.getlength ());                             MappingData.wrapperPath.setChars (Path.getbuffer (), Path.getstart (),                        Path.getlength ());                        MappingData.requestPath.setString (PATHSTR);                    MappingData.wrapperPath.setString (PATHSTR);        }}}} Path.setoffset (Servletpath);    Path.setend (Pathend); }}//Rule 4d--I call it rule 4d (source does not write) if (Mappingdata.wrapper = = null) {Boolean checkwelcomefiles = Checkjspwelcomefi    Les        if (!checkwelcomefiles) {char[] buf = Path.getbuffer ();    Checkwelcomefiles = (Buf[pathend-1] = = '/'); } if (Checkwelcomefiles) {for (int i = 0;                (I < ContextVersion.welcomeResources.length) && (Mappingdata.wrapper = = null);            i++) {path.setoffset (pathoffset);            Path.setend (Pathend);            Path.append (Contextversion.welcomeresources[i], 0, Contextversion.welcomeresources[i].length ());            Path.setoffset (Servletpath);        Internalmapextensionwrapper (extensionwrappers, Path, Mappingdata, false);        } path.setoffset (Servletpath);    Path.setend (Pathend); }}

As can be seen from the above, where path is no longer the original path, but our access to the path configured in Path+welcome-file, as a new path, for the welcome resources, but also broken down 4 rules, respectively, as follows:

    • 4a: Precise matching of new paths

    • 4b: Wildcard matching for a new path

    • 4c: Depending on the new path, find out if there is a corresponding file, if there is a corresponding file, you need to return the file. Before returning we need to further confirm that this file is not the source of the file content to return, or like a JSP file, do some processing and then return, so you have to confirm the file extension is what

      • 4C1: Try to find a servlet that can handle the file extension, that is, to match the extension and, if found, use the corresponding servlet
      • 4C2: If not found, the default is to use Defaultwrapper, that is defaultservlet (it will only return the file content source, do not do any processing)
    • 4d: The new path to the extension match (with the purpose of 4c, the main purpose of 4c is to return the contents of a file, before the return of the content related to the extension match, so 4c is the premise of the existence of the corresponding path of the file)

With the above rules, let's take a closer look at the 4 cases above which is the rule

    • Case 1:A.HTML,4A, 4b did not match to 4c time, found the file, and then try to match the extension, to decide whether to go 4c1 or 4c2, because. html does not have a corresponding servlet to handle, it uses the default Defaultservlet

    • Case 2:a.jsp, Ibid., when walking to 4c, found the processing. JSP corresponding to the servlet, so went 4c1

    • Case 3:a.action, If the root directory has a a.action file, then go to 4c1, the extension matches, matching to Secondservlet, that is, go 4c1, use Secondservlet to process the request, if there is no A.action file in the root directory, then went to 4d, the extension matches, the same match to Secondservlet, which goes 4d, also uses Secondservlet to process requests

    • Case 4:FIRST/ABC, when executing 4b, matches to Firstservlet, so use Firstservlet to process the request

At this point, the welcome-file-list thoroughly clear, have any questions and questions, welcome to ask questions

4 concluding remarks

After learning about Tomcat's Url-pattern rules, the next article will explain how SPRINGMVC handles static resources and their comprehensive analysis.

The source analysis of Tomcat's Url-pattern

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.