栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

彻底理解servlet匹配顺序 / 和 /*的区别

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

彻底理解servlet匹配顺序 / 和 /*的区别

本文内容基于Tomcat8
先看一下tomcat是怎么保存servlet的路径的。理解了这个再理解匹配顺序就很简单了。
每个servlet在tomcat中是由一个wrapper表示的,由这个wrapper去进行servlet的加载,执行等操作。简单理解的话把wrapper当成servlet也行。所以添加一个servlet到context中就是添加一个wrapper。tomcat根据servlet配置的映射路径把wrapper分成四类。

MapperWrapper包含一个name和一个wrapper,就像一个k v键值对,用来保存它们之间的映射关系。
首先看看解析web.xml文件,把servlet添加到context的过程。

添加servlet
解析web.xml,添加wrapper到context中的过程大致如下。根据servlet的映射路径得到一个name,把servlet包装成wrapper,把name和wrapper存到一个新的MapperWrapper里面。根据映射路径不同这个MapperWrapper会被存到四个地方:

    映射路径以/*结束:把MapperWrapper存到wildcardWrappers数组中。 name是 /*之前的部分映射路径以*.开始:把MapperWrapper存到extensionWrappers数组中 。 name是 *.之后的部分映射路径是 /:把MapperWrapper赋值给defaultWrapper。 name是空字符串其余的:把MapperWrapper存到exactWrappers数组中。 如果映射路径为空,把name设为/,其它就是映射路径本身

匹配顺序
从请求url找servlet的过程就是依次遍历图中的这三种MapperWrapper数组和defaultWrapper,根据url匹配name,匹配成功了就返回它对应的wrapper。

    遍历exactWrappers数组。完全匹配。遍历wildcardWrappers数组。前缀匹配。遍历extensionWrappers数组。后缀名匹配。匹配defaultWrapper。默认匹配。

这样区分/ 和 /* 就很简单了。 / 会把DispatcherServlet保存成Default wrapper,对应默认匹配,/ * 会把DispatcherServlet保存成Wildcard wrapper,对应前缀匹配。所以如果配成/*,那就是会把所有的请求都匹配到DispatcherServlet中。如果配成/,那就会先匹配tomcat自带的一些servlet,比如一些后缀匹配servlet(.jsp之类的)。

源码部分

添加servlet部分

// org/apache/catalina/mapper/Mapper.java

protected void addWrapper(ContextVersion context, String path,
                          Wrapper wrapper, boolean jspWildCard, boolean resourceOnly) {

    synchronized (context) {
        if (path.endsWith("/*")) {
            // Wildcard wrapper
            String name = path.substring(0, path.length() - 2);
            MappedWrapper newWrapper = new MappedWrapper(name, wrapper,
                    jspWildCard, resourceOnly);
            MappedWrapper[] oldWrappers = context.wildcardWrappers;
            MappedWrapper[] newWrappers = new MappedWrapper[oldWrappers.length + 1];
            if (insertMap(oldWrappers, newWrappers, newWrapper)) {
                context.wildcardWrappers = newWrappers;
                int slashCount = slashCount(newWrapper.name);
                if (slashCount > context.nesting) {
                    context.nesting = slashCount;
                }
            }
        } else if (path.startsWith("*.")) {
            // Extension wrapper
            String name = path.substring(2);
            MappedWrapper newWrapper = new MappedWrapper(name, wrapper,
                    jspWildCard, resourceOnly);
            MappedWrapper[] oldWrappers = context.extensionWrappers;
            MappedWrapper[] newWrappers =
                    new MappedWrapper[oldWrappers.length + 1];
            if (insertMap(oldWrappers, newWrappers, newWrapper)) {
                context.extensionWrappers = newWrappers;
            }
        } else if (path.equals("/")) {
            // Default wrapper
            MappedWrapper newWrapper = new MappedWrapper("", wrapper,
                    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 as an exact match
                name = "/";
            } else {
                name = path;
            }
            MappedWrapper newWrapper = new MappedWrapper(name, wrapper,
                    jspWildCard, resourceOnly);
            MappedWrapper[] oldWrappers = context.exactWrappers;
            MappedWrapper[] newWrappers = new MappedWrapper[oldWrappers.length + 1];
            if (insertMap(oldWrappers, newWrappers, newWrapper)) {
                context.exactWrappers = newWrappers;
            }
        }
    }
}

匹配部分 (省略了一些代码和Welcome resources的匹配过程)

// org/apache/catalina/mapper/Mapper.java
private final void internalMapWrapper(ContextVersion contextVersion,
                                          CharChunk path,
                                          MappingData mappingData) {

      // Rule 1 -- Exact Match
       MappedWrapper[] exactWrappers = contextVersion.exactWrappers;
       internalMapExactWrapper(exactWrappers, path, mappingData);

       // Rule 2 -- Prefix Match
       boolean checkJspWelcomeFiles = false;
       MappedWrapper[] wildcardWrappers = contextVersion.wildcardWrappers;
       internalMapWildcardWrapper(wildcardWrappers, contextVersion.nesting,
                   path, mappingData);

		// Rule 3 -- Extension Match
       MappedWrapper[] extensionWrappers = contextVersion.extensionWrappers;
       internalMapExtensionWrapper(extensionWrappers, path, mappingData,
                   true);
      
       // Rule 4 -- Default servlet
		mappingData.wrapper = contextVersion.defaultWrapper.object;
   }
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/769087.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号