2

http://download.oracle.com/otn-pub/jcp/servlet-3.0-fr-oth-JSpec/servlet-3_0-final-spec.pdf

这将在第 12 章:将请求映射到 Servlet 中。我查看了 JBoss 的 Maven 存储库,虽然规范接口可用,但我似乎无法找到 12.1 和 12.2 关于 servlet url 模式匹配的底层实现。我有兴趣查看表达式如何映射到另一个项目的规则。

4

2 回答 2

3

我正在考虑 Tomcat 7.0.42。以下答案中的链接指向 grepcode.com 中的 7.0.42 源代码。

servlet 映射在应用程序启动期间被解析并添加为其中的源代码Wrapperorg.apache.tomcat.util.http.mapper.Mapper#addWrapper()此处复制粘贴(注意:术语“包装器”在这里基本上代表“映射的 servlet”):

360     protected void addWrapper(ContextVersion context, String path,
361             Object wrapper, boolean jspWildCard, boolean resourceOnly) {
362 
363         synchronized (context) {
364             Wrapper newWrapper = new Wrapper();
365             newWrapper.object = wrapper;
366             newWrapper.jspWildCard = jspWildCard;
367             newWrapper.resourceOnly = resourceOnly;
368             if (path.endsWith("/*")) {
369                 // Wildcard wrapper
370                 newWrapper.name = path.substring(0, path.length() - 2);
371                 Wrapper[] oldWrappers = context.wildcardWrappers;
372                 Wrapper[] newWrappers =
373                     new Wrapper[oldWrappers.length + 1];
374                 if (insertMap(oldWrappers, newWrappers, newWrapper)) {
375                     context.wildcardWrappers = newWrappers;
376                     int slashCount = slashCount(newWrapper.name);
377                     if (slashCount > context.nesting) {
378                         context.nesting = slashCount;
379                     }
380                 }
381             } else if (path.startsWith("*.")) {
382                 // Extension wrapper
383                 newWrapper.name = path.substring(2);
384                 Wrapper[] oldWrappers = context.extensionWrappers;
385                 Wrapper[] newWrappers =
386                     new Wrapper[oldWrappers.length + 1];
387                 if (insertMap(oldWrappers, newWrappers, newWrapper)) {
388                     context.extensionWrappers = newWrappers;
389                 }
390             } else if (path.equals("/")) {
391                 // Default wrapper
392                 newWrapper.name = "";
393                 context.defaultWrapper = newWrapper;
394             } else {
395                 // Exact wrapper
396                 if (path.length() == 0) {
397                     // Special case for the Context Root mapping which is
398                     // treated as an exact match
399                     newWrapper.name = "/";
400                 } else {
401                     newWrapper.name = path;
402                 }
403                 Wrapper[] oldWrappers = context.exactWrappers;
404                 Wrapper[] newWrappers =
405                     new Wrapper[oldWrappers.length + 1];
406                 if (insertMap(oldWrappers, newWrappers, newWrapper)) {
407                     context.exactWrappers = newWrappers;
408                 }
409             }
410         }
411     }

在处理传入的 HTTP 请求时,通过映射查找 servlet 的所有魔力都始于org.apache.catalina.connector.CoyoteAdapter#postParseRequest().

647        connector.getMapper().map(serverName, decodedURI, version,
648                                  request.getMappingData());
649        request.setContext((Context) request.getMappingData().context);
650        request.setWrapper((Wrapper) request.getMappingData().wrapper);

第 647 行间接调用org.apache.tomcat.util.http.mapper.Mapper #internalMapWrapper(),这是当前 HTTP 请求的映射数据用ContextWrapper(本质上是可用的 servlet 实例)填充的地方。代码挺多的,这里就不复制粘贴了,直接点击grepcode链接即可。

然后,第 649 行和第 650 行基本上设置了映射ContextWrapper当前请求。Context保存具体ServletContext实例,保存Wrapper具体Servlet实例作为属性,org.apache.catalina.core.Wrapper#instance

最后,在调用所有过滤器之后,ApplicationFilterChain将调用 servlet 的service()方法。


对于我自己的项目OmniFaces JSF 实用程序库,我曾经在WebXml实用程序类中根据 servlet 规范 12.1 实现了匹配检查(以相当简化的形式)。这些可能对您也有帮助,源代码在这里,相关摘录如下:

private static boolean isExactMatch(String urlPattern, String url) {
    return url.equals(urlPattern.endsWith("/*") ? urlPattern.substring(0, urlPattern.length() - 2) : urlPattern);
}

private static boolean isPrefixMatch(String urlPattern, String url) {
    return urlPattern.endsWith("/*") ? url.startsWith(urlPattern.substring(0, urlPattern.length() - 2)) : false;
}

private static boolean isSuffixMatch(String urlPattern, String url) {
    return urlPattern.startsWith("*.") ? url.endsWith(urlPattern.substring(1)) : false;
}
于 2013-08-29T19:13:02.137 回答
-2

这取决于模式匹配发生的位置。如果您打算让 JBoss(Tomcat 真的,Mohammad 对此非常正确)处理 Web.xml 中的所有 url 映射,并且仅设置这些映射来处理特定端点上的请求,那么 org.apache.naming 可能就足够了为您的目的。

虽然,我可能会从NamingContext.java开始作为一个好的起点。不是特别令人兴奋,它处理它的方式就像您想象的那样,使用名称关联(绑定)的 HashMap 和对象关联(上下文环境)的 HashTable,仍然是绑定和查找发生的地方。

但是,如果您希望通过前端控制器处理自己的路由,或者想要动态重定向或重新映射,那么Tomcat 8 Servlet 3.0 API文档可能更符合您的要求,它也是您的实现信息在您的问题中要求。

希望有帮助。

于 2013-08-28T05:32:18.997 回答