Servlet容器Tomcat中l中url-pattern的配置详解[附带源
码分析]
今天研究了⼀下tomcat上l配置⽂件中url-pattern的问题。
这个问题其实毕业前就困扰着我,当时忙于找⼯作。找到⼯作之后⼀直忙,也就没时间顾虑这个问题了。说到底还是⾃⼰懒了,没花时间来研究。
今天看了tomcat的部分源码了解了这个url-pattern的机制。下⾯让我⼀⼀道来。
tomcat的⼤致结构就不说了,毕竟⾃⼰也不是特别熟悉。有兴趣的同学请⾃⾏查看相关资料。等有时间了我会来补充这部分的知识的。
想要了解url-pattern的⼤致配置必须了解at.util.http.mapper.Mapper这个类
这个类的源码注释:Mapper, which implements the rvlet API mapping rules (which are derived from the HTTP rules). 意思也就是说
“Mapper是⼀个衍⽣⾃HTTP规则并实现了rvlet API映射规则的类”。
⾸先先看我们定义的⼏个Servlet:
<rvlet>
<rvlet-name>ExactServlet</rvlet-name>
<rvlet-class>org.format.urlpattern.ExactServlet</rvlet-class>
</rvlet>
<rvlet-mapping>
<rvlet-name>ExactServlet</rvlet-name>
<url-pattern>/exact.do</url-pattern>
</rvlet-mapping>
residentflash
<rvlet>
<rvlet-name>ExactServlet2</rvlet-name>
<rvlet-class>org.format.urlpattern.ExactServlet2</rvlet-class>生活需要善意的谎言
</rvlet>
<rvlet-mapping>
<rvlet-name>ExactServlet2</rvlet-name>
<url-pattern>/exact2.do</url-pattern>
</rvlet-mapping>
<rvlet>dovetail
spandex<rvlet-name>TestAllServlet</rvlet-name>
<rvlet-class>org.format.urlpattern.TestAllServlet</rvlet-class>
</rvlet>
<rvlet-mapping>
<rvlet-name>TestAllServlet</rvlet-name>
<url-pattern>/*</url-pattern>
</rvlet-mapping>
<rvlet>
<rvlet-name>TestServlet</rvlet-name>
<rvlet-class>org.format.urlpattern.TestServlet</rvlet-class>
</rvlet>
<rvlet-mapping>
<rvlet-name>TestServlet</rvlet-name>
十二的英文<url-pattern>/</url-pattern>
</rvlet-mapping>
有4个Servlet。分别是2个精确地址的Servlet:ExactServlet和ExactServlet2。 1个urlPattern为 “/*” 的TestAllServlet,1个urlPattern为 "/" 的TestServlet。日久见人心的英文
我们先来看现象:
两个精确地址的Servlet都没问题。找到并匹配了。
test.do这个地址并不存在,因为没有相应的精确的urlPattern。所以tomcat选择urlPattern为 "/*" 的Servlet进⾏处理。
index.jsp(这个⽂件tomcat是存在的),也被urlPattern为 "/*" 的Servlet进⾏处理。
成都英语学习我们发现,精确地址的urlPattern的优先级⾼于/*, "/" 规则的Servlet没被处理。
为什么呢? 开始分析源码。
本次源码使⽤的tomcat版本是7.0.52.
tomcat在启动的时候会扫描l⽂件。 WebXml这个类是扫描l⽂件的,然后得到rvlet的映射数据rvletMappings。
然后会调⽤Context(实现类为StandardContext)的addServletMapping⽅法。这个⽅法会调⽤本⽂开头提到的Mapper的addWrapper⽅法,这个⽅法在源码Mapper的360⾏。
这⾥,我们可以看到路径分成4类。
1. 以 /* 结尾的。 dsWith("/*")
2. 以 *. 开头的。 path.startsWith("*.")
3. 是否是 /。 path.equals("/")
4. 以上3种之外的。
各种对应的处理完成之后,会存⼊context的各种wrapper中。这⾥的context是ContextVersion,这是⼀个定义在Mapper内部的静态类。
它有4种wrapper。 defaultWrapper,exactWrapper, wildcardWrappers,extensionWrappers。华中师范大学自考
这⾥的Wrapper概念:
Wrapper 代表⼀个 Servlet,它负责管理⼀个 Servlet,包括的 Servlet 的装载、初始化、执⾏以及资源回收。回过头来看mapper的addWrapper⽅法:
1. 我们看到 /* 对应的Servlet会被丢到wildcardWrappers中
2. *. 会被丢到extensionWrappers中
3. / 会被丢到defaultWrapper中
4. 其他的映射都被丢到exactWrappers中
最终debug看到的这些wrapper也验证了我们的结论。
这⾥多了2个扩展wrapper,tomcat默认给我们加⼊的,分别处理.jsp和.jspx。
好了。在这之前都是tomcat启动的时候做的⼀些⼯作。
下⾯开始看⽤户请求的时候tomcat是如何⼯作的:ipart
⽤户请求过来的时候会调⽤mapper的internalMapWrapper⽅法, Mapper源码830⾏。
// Rule 1 -- Exact Match会计法规
Wrapper[] exactWrappers = actWrappers;
internalMapExactWrapper(exactWrappers, path, mappingData);
// Rule 2 -- Prefix Match
boolean checkJspWelcomeFiles = fal;
Wrapper[] wildcardWrappers = contextVersion.wildcardWrappers;
if (mappingData.wrapper == null) {
internalMapWildcardWrapper(wildcardWrappers, sting,