本文所要解决的问题:一个http请求过来,容器是怎么知道选择哪个具体servlet?
我们知道,一个Context容器表示一个web应用,一个Wrapper容器表示一个servlet,所以上面的问题可以转换为怎么由Context容器选择servlet,答案是映射器。映射器是实现了Mapper接口的类,作用就是根据请求连接(主要是协议和路径)来选择下一个容器,可以看做是一个哈希表,根据关键字段来选择具体的值,Mapper接口的定义为:
public interface Mapper {
public Container getContainer();//返回与该映射器相关联的容器
public void setContainer(Container container);
public String getProtocol();//返回与该映射器处理的协议
public void setProtocol(String protocol);
public Container map(Request request, boolean update); //映射函数,实现该函数
}
在Tomcat源码分析(四)--容器处理链接之责任链模式中已经知道,请求连接到达StandardContext容器的invoke方法,最终会到达StandardContextValue阀的invoke方法里面,在这个invoke方法中有一句这样的代码:
wrapper = (Wrapper) context.map(request, true);
这句代码表示容器会调用map方法来映射请求到具体的wrapper上,意思就是说,根据连接请求request来选择wrapper。上面的map会调用父类ContainerBase的map方法来找到具体的映射器,至于这个映射器和容器是怎么关联上的,具体请参考 Tomcat源码分析(三)--连接器是如何与容器关联的?这篇文章,大致原理是一样的。StandardContext容器有一个标准的映射器实现类StandardContextMapper,所以最终会调用到映射器StandardContextMapper的map方法,这个方法是选择servlet的关键(省略了一些代码):
public Container map(Request request, boolean update) {
// Identify the context-relative URI to be mapped
String contextPath =
((HttpServletRequest) request.getRequest()).getContextPath();
String requestURI = ((HttpRequest) request).getDecodedRequestURI();
String relativeURI = requestURI.substring(contextPath.length());
// Apply the standard request URI mapping rules from the specification
Wrapper wrapper = null;
String servletPath = relativeURI;
String pathInfo = null;
String name = null;
// Rule 1 -- Exact Match
if (wrapper == null) {
if (debug >= 2)
context.log(" Trying exact match");
if (!(relativeURI.equals("/")))
name = context.findServletMapping(relativeURI);
if (name != null)
wrapper = (Wrapper) context.findChild(name);
if (wrapper != null) {
servletPath = relativeURI;
pathInfo = null;
}
}
// Rule 2 -- Prefix Match
if (wrapper == null) {
if (debug >= 2)
context.log(" Trying prefix match");
servletPath = relativeURI;
while (true) {
name = context.findServletMapping(servletPath + "/*");
if (name != null)
wrapper = (Wrapper) context.findChild(name);
if (wrapper != null) {
pathInfo = relativeURI.substring(servletPath.length());
if (pathInfo.length() == 0)
pathInfo = null;
break;
}
int slash = servletPath.lastIndexOf('/');
if (slash < 0)
break;
servletPath = servletPath.substring(0, slash);
}
}
// Rule 3 -- Extension Match
if (wrapper == null) {
if (debug >= 2)
context.log(" Trying extension match");
int slash = relativeURI.lastIndexOf('/');
if (slash >= 0) {
String last = relativeURI.substring(slash);
int period = last.lastIndexOf('.');
if (period >= 0) {
String pattern = "*" + last.substring(period);
name = context.findServletMapping(pattern);
if (name != null)
wrapper = (Wrapper) context.findChild(name);
if (wrapper != null) {
servletPath = relativeURI;
pathInfo = null;
}
}
}
}
// Rule 4 -- Default Match
if (wrapper == null) {
if (debug >= 2)
context.log(" Trying default match");
name = context.findServletMapping("/");
if (name != null)
wrapper = (Wrapper) context.findChild(name);
if (wrapper != null) {
servletPath = relativeURI;
pathInfo = null;
}
}
}
代码很长,但是很容易看懂,就是分4中匹配模式(完全匹配,前缀匹配,扩展匹配,默认匹配)来选择wrapper,关键代码就是name = context.findServletMapping和wrapper = (Wrapper) context.findChild(name);这里面context都是StandardContext。context.findServletMapping是根据匹配模式来找到servlet名字,context.findChild是根据servlet名字找到具体的wrapper。findServletMapping方法很简单,就是在一个HashMap里面得到servlet名字,代码如下,其中servletMappings是一个HashMap:
public String findServletMapping(String pattern) {
synchronized (servletMappings) {
return ((String) servletMappings.get(pattern));
}
}
findChild方法跟findServletMapping方法一样,也是在一个HashMap找wrapper容器。至此,已经能够回答一开始的问题了,StandardContext容器根据映射器来选择wrapper。当然,容器Engine和Host也是根据映射器来选择它们的下一级容器的。
分享到:
相关推荐
Tomcat源码分析有助于识别性能瓶颈,例如调整线程池大小、缓存策略、连接器设置等。此外,了解如何配置和使用NIO或APR(Apache Portable Runtime)连接器可以显著提升Tomcat的并发处理能力。 8. **故障排查** ...
- **处理请求**:Tomcat worker接收到请求后,通过Servlet容器处理它。 - **返回响应**:Tomcat完成处理后,将响应通过`mod_jk`回传给HTTPD,最后由HTTPD发送回客户端。 5. **性能优化** `tomcat-connectors-...
Servlet容器,如Tomcat、Jetty等,负责管理和运行Servlet。它们根据web.xml或注解配置加载Servlet,并通过DispatcherServlet进行请求分发。DispatcherServlet是Spring MVC的核心组件,它实现了Servlet API并负责调度...
Apache Tomcat 8.5.23 源码分析 Apache Tomcat 是一个开源的、免费的Web服务器和Servlet容器,它实现了Java Servlet和JavaServer Pages(JSP)规范,是开发和部署Java Web应用的重要平台。深入理解Tomcat的源码有助...
通过对Catalina Home的源码分析,我们可以深入理解Tomcat如何加载和解析配置,如何管理Web应用,以及如何处理请求和响应。这对于优化应用性能、调试问题以及扩展Tomcat功能都有着极大的帮助。 总的来说,掌握Tomcat...
五、源码分析 Servlet的实现需要继承`javax.servlet.http.HttpServlet`类或实现`javax.servlet.Servlet`接口。以下是一个简单的Servlet示例: ```java import javax.servlet.*; import javax.servlet.http.*; ...
5. **Tomcat源码分析** 对于Tomcat的实现细节,主要关注以下几点: - **启动/初始化**:Tomcat启动时会解析web.xml,创建并初始化应用的组件。 - **并发线程模式**:Tomcat使用线程池来处理并发请求,提高性能。 ...
【标题】"Tomcat 8源代码 Servlet源代码" 涉及到的是Apache Tomcat服务器的源码分析,特别是Servlet容器的相关实现。Tomcat是一个开源的轻量级Web应用服务器,广泛用于部署Java Servlet和JavaServer Pages (JSP)应用...
通过分析和学习Servlet源码,可以深入了解HTTP请求的处理流程,以及如何利用Servlet API构建动态Web应用。同时,对于Java Web开发的深入理解和优化具有重要意义。在实际项目中,了解Servlet的工作原理有助于更好地...
Wrapper会根据Servlet映射找到对应的Servlet实例,执行Servlet的service方法来处理请求。 4. **线程模型**:Tomcat使用了多种线程模型,如 Coyote、NIO 和 APR,以适应不同的性能需求。通过源码,我们可以看到如何...
Servlet源码的分析能帮助我们深入理解HTTP请求处理流程、服务器生命周期管理以及Java Web开发的底层机制。Apache Tomcat是一款广泛应用的Servlet容器,它实现了Java Servlet和JavaServer Pages(JSP)规范。在这里,...
总结来说,Tomcat源码剖析的学习,将帮助读者理解servlet容器的内部运行机制,了解Tomcat架构的模块化设计原理,掌握如何配置和自定义Tomcat服务器,并为可能参与Tomcat的开发工作提供必要的技术储备。通过对各个...
- 深入阅读Tomcat源码有助于理解其工作原理,例如`org.apache.catalina.connector.Request`和`org.apache.catalina.connector.Response`类是处理请求和响应的核心。 - `org.apache.catalina.Context`和`org.apache...
八、源码分析 对于学习和调试Servlet,理解其内部源码非常有益。例如,`HttpServletRequest`和`HttpServletResponse`是如何封装HTTP请求和响应的,`service()`方法如何根据请求类型选择适当的方法执行等。 九、实战...
这两个方法是Servlet生命周期的一部分,当用户通过浏览器发送请求时,Servlet容器(如Tomcat)会调用相应的请求处理方法。 接着,我们来看源码文件中的关键点。韩顺平老师的源码可能会包含以下内容: 1. **Servlet...
《如何让Tomcat工作:中文版(源码)》是一份深入探讨Web服务器Tomcat工作原理的资源,其中包含了详细的理论讲解以及配套的源码分析。这份资料旨在帮助读者理解Tomcat内部机制,从而能够更好地优化和调试应用程序。 ...
6. **源码分析**: 拥有源码jar包意味着你可以查看Servlet API的内部实现,理解其工作原理,这对于学习和优化代码非常有帮助。例如,你可以研究`HttpServletRequest`和`HttpServletResponse`是如何处理HTTP请求和...
Servlet是Java Web开发中的核心组件,它是一种...结合源码分析和适当的工具,如调试器和日志记录,可以更好地理解和优化Servlet的性能。在实际项目中,熟练运用Servlet能帮助开发者构建出功能强大、扩展性强的Web应用。
源码分析对于深入理解Servlet的工作原理至关重要。在这个`servlet源码`的压缩包中,我们有`tomcat-6-src`,这包含了Apache Tomcat 6的源代码,一个流行的Servlet容器实现。 Apache Tomcat是一个开源的Web应用服务器...