Servlet容器Tomcat中web.xml中url-pattern设置详解
当前位置:以往代写 > JAVA 教程 >Servlet容器Tomcat中web.xml中url-pattern设置详解
2019-06-14

Servlet容器Tomcat中web.xml中url-pattern设置详解

Servlet容器Tomcat中web.xml中url-pattern设置详解

副标题#e#

媒介

本日研究了一下tomcat上web.xml设置文件中url-pattern的问题。

这个问题其实结业前就困扰着我,其时忙于谋事情。 找到事情之后一直忙,也就没时间记挂这个问题了。 说到底照旧本身懒了,没花时间来研究。

本日看了tomcat的部门源码 相识了这个url-pattern的机制。  下面让我一一道来。

tomcat的大抵布局就不说了, 究竟本身也不是出格熟悉。 有乐趣的同学请自行查察相关资料。 等有时间了我会来增补这部门的常识的。

想要相识url-pattern的大抵设置必需相识org.apache.tomcat.util.http.mapper.Mapper这个类

这个类的源码注释:Mapper, which implements the servlet API mapping rules (which are derived from the HTTP rules).  意思也就是说  “Mapper是一个衍生自HTTP法则并实现了servlet API映射法则的类”。

现象

首先先看我们界说的几个Servlet:

<servlet>
        <servlet-name>ExactServlet</servlet-name>
        <servlet-class>org.format.urlpattern.ExactServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ExactServlet</servlet-name>
        <url-pattern>/exact.do</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>ExactServlet2</servlet-name>
        <servlet-class>org.format.urlpattern.ExactServlet2</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ExactServlet2</servlet-name>
        <url-pattern>/exact2.do</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>TestAllServlet</servlet-name>
        <servlet-class>org.format.urlpattern.TestAllServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>TestAllServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>TestServlet</servlet-name>
        <servlet-class>org.format.urlpattern.TestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>TestServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

有4个Servlet。 别离是2个准确地点的Servlet:ExactServlet和ExactServlet2。 1个urlPattern为 “/*” 的TestAllServlet,1个urlPattern为 "/" 的TestServlet。

我们先来看现象:

Servlet容器Tomcat中web.xml中url-pattern配置详解Servlet容器Tomcat中web.xml中url-pattern配置详解

两个准确地点的Servlet都没问题。 找到并匹配了。

Servlet容器Tomcat中web.xml中url-pattern配置详解Servlet容器Tomcat中web.xml中url-pattern配置详解


#p#副标题#e#

test.do这个地点并不存在,因为没有相应的准确的urlPattern。  所以tomcat选择urlPattern为 "/*" 的Servlet举办处理惩罚。

index.jsp(这个文件tomcat是存在的), 也被urlPattern为 "/*" 的Servlet举办处理惩罚。

我们发明,准确地点的urlPattern的优先级高于/*, "/" 法则的Servlet没被处理惩罚。

为什么呢? 开始阐明源码。

源码阐明

本次源码利用的tomcat版本是7.0.52.

tomcat在启动的时候会扫描web.xml文件。 WebXml这个类是扫描web.xml文件的,然后获得servlet的映射数据servletMappings。

Servlet容器Tomcat中web.xml中url-pattern配置详解

然后会挪用Context(实现类为StandardContext)的addServletMapping要领。 这个要了解挪用本文开头提到的Mapper的addWrapper要领,这个要领在源码Mapper的360行。

Servlet容器Tomcat中web.xml中url-pattern配置详解

这里,我们可以看到路径分成4类。

1.  以 /* 末了的。 path.endsWith("/*")

2.  以 *. 开头的。 path.startsWith("*.")

3.  是否是 /。      path.equals("/")

4.  以上3种之外的。

各类对应的处理惩罚完成之后,会存入context的各类wrapper中。这里的context是ContextVersion,这是一个界说在Mapper内部的静态类。

Servlet容器Tomcat中web.xml中url-pattern配置详解

它有4种wrapper。 defaultWrapper,exactWrapper, wildcardWrappers,extensionWrappers。

这里的Wrapper观念:

Wrapper 代表一个 Servlet,它认真打点一个 Servlet,包罗的 Servlet 的装载、初始化、执行以及资源接纳。

#p#副标题#e#

回过甚来看mapper的addWrapper要领:

1. 我们看到  /* 对应的Servlet会被丢到wildcardWrappers中

2. *. 会被丢到extensionWrappers中

3. / 会被丢到defaultWrapper中

4. 其他的映射都被丢到exactWrappers中

最终debug看到的这些wrapper也验证了我们的结论。

Servlet容器Tomcat中web.xml中url-pattern配置详解

这里多了2个扩展wrapper,tomcat默认给我们插手的,别离处理惩罚.jsp和.jspx。

好了。 在这之前都是tomcat启动的时候做的一些事情。

下面开始看用户请求的时候tomcat是如何事情的:

#p#分页标题#e#

用户请求过来的时候会挪用mapper的internalMapWrapper要领, Mapper源码830行。

// 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);
            .....
        }
    
        ....// 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;
            if (!checkWelcomeFiles) {
                char[] buf = path.getBuffer();
                checkWelcomeFiles = (buf[pathEnd - 1] == '/');
            }
            if (checkWelcomeFiles) {
                for (int i = 0; (i < contextVersion.welcomeResources.length)
                         && (mappingData.wrapper == null); i++) {
                    ...// Rule 4a -- Welcome resources processing for exact macth
                    internalMapExactWrapper(exactWrappers, path, mappingData);
    
                    // Rule 4b -- Welcome resources processing for prefix match
                    if (mappingData.wrapper == null) {
                        internalMapWildcardWrapper
                            (wildcardWrappers, contextVersion.nesting,
                             path, mappingData);
                    }
    
                    // Rule 4c -- Welcome resources processing
                    //            for physical folder
                    if (mappingData.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);
            }
    
        }
    
        /* welcome file processing - take 2
         * Now that we have looked for welcome files with a physical
         * backing, now look for an extension mapping listed
         * but may not have a physical backing to it. This is for
         * the case of index.jsf, index.do, etc.
         * A watered down version of rule 4
         */
        if (mappingData.wrapper == null) {
            boolean checkWelcomeFiles = checkJspWelcomeFiles;
            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);
            }
        }
    
    
        // 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());
            }
            ...
        }

#p#副标题#e#

这段代码作者已经为我们写好了注释.

Rule1,Rule2,Rule3….

看代码我们大抵得出了:

用户请求这里举办url匹配的时候是有优先级的。 我们从上到下以优先级的坎坷举办说明:

法则1:准确匹配,利用contextVersion的exactWrappers

法则2:前缀匹配,利用contextVersion的wildcardWrappers

法则3:扩展名匹配,利用contextVersion的extensionWrappers

法则4:利用资源文件来处理惩罚servlet,利用contextVersion的welcomeResources属性,这个属性是个字符串数组

法则7:利用默认的servlet,利用contextVersion的defaultWrapper

最终匹配到的wrapper(其实也就是servlet)会被丢到MappingData中举办后续处理惩罚。

下面验证我们的结论:

#p#分页标题#e#

我们在设置文件中去掉 /* 的TestAllServlet这个Servlet。 然后会见index.jsp。 这个时候法则1准确匹配没有找到,法则2前缀匹配由于去掉了TestAllServlet,因此为null,法则3扩展名匹配(tomcat自动为我们插手的处理惩罚.jsp和.jspx路径的)匹配乐成。最后会输出index.jsp的内容。

Servlet容器Tomcat中web.xml中url-pattern配置详解

验证乐成。

我们再来验证http://localhost:7777/UrlPattern_Tomcat/地点。(TestAllServlet依旧不存在)

Servlet容器Tomcat中web.xml中url-pattern配置详解

法则1,2前面已经说过,法则3是.jsp和.jspx。 法则4利用welcomeResources,这是个字符串数组,通过debug可以看到

Servlet容器Tomcat中web.xml中url-pattern配置详解

会默认取这3个值。最终会通过法则4.c匹配乐成,这部门各人可以本身查察源码阐明。

最后我们再来验证一个例子:

将TestAllServlet的urlpattern改为/test/*。

Servlet容器Tomcat中web.xml中url-pattern配置详解

Servlet容器Tomcat中web.xml中url-pattern配置详解

验证乐成。

#p#副标题#e#

实战例子

SpringMVC相信各人根基都用过了。 还不清楚的同学可以看看它的入门blog:http://www.cnblogs.com/fangjian0423/p/springMVC-introduction.html

SpringMVC是利用DispatcherServlet做为主分发器的。  这个Servlet对应的url-pattern一般城市用“/”,虽然用"/*"也是可以的,只是大概会有些别扭。

假如利用/*,本文已经阐明过这个url-pattern除了准确地点,其他地点都由这个Servlet执行。

好比这个http://localhost:8888/SpringMVCDemo/index.jsp那么就会进入SpringMVC的DispatcherServlet中举办处理惩罚,最终没有没有匹配到 /index.jsp 这个 RequestMapping, 办理要领呢  就是设置一个:

Servlet容器Tomcat中web.xml中url-pattern配置详解

最终没有跳到/webapp下的index.jsp页面,而是进入了SpringMVC设置的相应文件("/*"的优先级比.jsp高):

Servlet容器Tomcat中web.xml中url-pattern配置详解

虽然,这样有点别扭,究竟SpringMVC支持RESTFUL气势气魄的URL。

我们把url-pattern设置回 "/" 会见沟通的地点, 功效返回的是相应的jsp页面("/"的优先级比.jsp低)。

总结

之前这个url-pattern的问题本身也上网搜过相关的结论,网上的根基都是结论,本身看过一次之后过段时间就健忘了。说到底照旧不知道事情道理,只知道结论。并且恰好这方面的源码阐明范例博客今朝还未有人写过,于是这次本身也是抉择看看源码一探毕竟。

#p#分页标题#e#

总结: 想要相识某一机制的事情道理,最好的要领就是查察源码。然而查察源码就需要相识大量的常识点,这需要花必然的时间。可是当你看大白了那些源码之后,事情道理也就相当熟悉了, 就不需要去背别人写好的一些结论了。 发起各人多看看源码。

作者:cnblogs Format

    关键字:

在线提交作业