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 模式匹配的底层实现。我有兴趣查看表达式如何映射到另一个项目的规则。
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 模式匹配的底层实现。我有兴趣查看表达式如何映射到另一个项目的规则。
我正在考虑 Tomcat 7.0.42。以下答案中的链接指向 grepcode.com 中的 7.0.42 源代码。
servlet 映射在应用程序启动期间被解析并添加为其中的源代码Wrapper
在org.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 请求的映射数据用Context
和Wrapper
(本质上是可用的 servlet 实例)填充的地方。代码挺多的,这里就不复制粘贴了,直接点击grepcode链接即可。
然后,第 649 行和第 650 行基本上设置了映射Context
和Wrapper
当前请求。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;
}
这取决于模式匹配发生的位置。如果您打算让 JBoss(Tomcat 真的,Mohammad 对此非常正确)处理 Web.xml 中的所有 url 映射,并且仅设置这些映射来处理特定端点上的请求,那么 org.apache.naming 可能就足够了为您的目的。
虽然,我可能会从NamingContext.java开始作为一个好的起点。不是特别令人兴奋,它处理它的方式就像您想象的那样,使用名称关联(绑定)的 HashMap 和对象关联(上下文环境)的 HashTable,仍然是绑定和查找发生的地方。
但是,如果您希望通过前端控制器处理自己的路由,或者想要动态重定向或重新映射,那么Tomcat 8 Servlet 3.0 API文档可能更符合您的要求,它也是您的实现信息在您的问题中要求。
希望有帮助。