`
haitaoandroid
  • 浏览: 27473 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Tomcat源码分析(五)--容器处理连接之servlet的映射

 
阅读更多

本文所要解决的问题:一个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源码,servlet-api源码

    Tomcat源码分析有助于识别性能瓶颈,例如调整线程池大小、缓存策略、连接器设置等。此外,了解如何配置和使用NIO或APR(Apache Portable Runtime)连接器可以显著提升Tomcat的并发处理能力。 8. **故障排查** ...

    tomcat-connectors-1.2.48-src

    - **处理请求**:Tomcat worker接收到请求后,通过Servlet容器处理它。 - **返回响应**:Tomcat完成处理后,将响应通过`mod_jk`回传给HTTPD,最后由HTTPD发送回客户端。 5. **性能优化** `tomcat-connectors-...

    jakarta-servletapi-4-src.zip servlet源码

    Servlet容器,如Tomcat、Jetty等,负责管理和运行Servlet。它们根据web.xml或注解配置加载Servlet,并通过DispatcherServlet进行请求分发。DispatcherServlet是Spring MVC的核心组件,它实现了Servlet API并负责调度...

    tomcat8源码

    Apache Tomcat 8.5.23 源码分析 Apache Tomcat 是一个开源的、免费的Web服务器和Servlet容器,它实现了Java Servlet和JavaServer Pages(JSP)规范,是开发和部署Java Web应用的重要平台。深入理解Tomcat的源码有助...

    tomcat8.0源码+catalina-home.rar

    通过对Catalina Home的源码分析,我们可以深入理解Tomcat如何加载和解析配置,如何管理Web应用,以及如何处理请求和响应。这对于优化应用性能、调试问题以及扩展Tomcat功能都有着极大的帮助。 总的来说,掌握Tomcat...

    web容器---servlet

    五、源码分析 Servlet的实现需要继承`javax.servlet.http.HttpServlet`类或实现`javax.servlet.Servlet`接口。以下是一个简单的Servlet示例: ```java import javax.servlet.*; import javax.servlet.http.*; ...

    Tomcat(二) Tomcat实现:Servlet与web.xml介绍 以及 源码分析Tomcat实现细节1

    5. **Tomcat源码分析** 对于Tomcat的实现细节,主要关注以下几点: - **启动/初始化**:Tomcat启动时会解析web.xml,创建并初始化应用的组件。 - **并发线程模式**:Tomcat使用线程池来处理并发请求,提高性能。 ...

    Tomcat 8源代码 Servlet源代码

    【标题】"Tomcat 8源代码 Servlet源代码" 涉及到的是Apache Tomcat服务器的源码分析,特别是Servlet容器的相关实现。Tomcat是一个开源的轻量级Web应用服务器,广泛用于部署Java Servlet和JavaServer Pages (JSP)应用...

    servlet 源码

    通过分析和学习Servlet源码,可以深入了解HTTP请求的处理流程,以及如何利用Servlet API构建动态Web应用。同时,对于Java Web开发的深入理解和优化具有重要意义。在实际项目中,了解Servlet的工作原理有助于更好地...

    Tomcat源码 学习java很好的东东 apache-tomcat-6.0.26-src

    Wrapper会根据Servlet映射找到对应的Servlet实例,执行Servlet的service方法来处理请求。 4. **线程模型**:Tomcat使用了多种线程模型,如 Coyote、NIO 和 APR,以适应不同的性能需求。通过源码,我们可以看到如何...

    Servlet源码

    Servlet源码的分析能帮助我们深入理解HTTP请求处理流程、服务器生命周期管理以及Java Web开发的底层机制。Apache Tomcat是一款广泛应用的Servlet容器,它实现了Java Servlet和JavaServer Pages(JSP)规范。在这里,...

    tomcat源码剖析pdf,想学的帮助挺大的

    总结来说,Tomcat源码剖析的学习,将帮助读者理解servlet容器的内部运行机制,了解Tomcat架构的模块化设计原理,掌握如何配置和自定义Tomcat服务器,并为可能参与Tomcat的开发工作提供必要的技术储备。通过对各个...

    tomcat工作原理-框架

    - 深入阅读Tomcat源码有助于理解其工作原理,例如`org.apache.catalina.connector.Request`和`org.apache.catalina.connector.Response`类是处理请求和响应的核心。 - `org.apache.catalina.Context`和`org.apache...

    Servlet

    八、源码分析 对于学习和调试Servlet,理解其内部源码非常有益。例如,`HttpServletRequest`和`HttpServletResponse`是如何封装HTTP请求和响应的,`service()`方法如何根据请求类型选择适当的方法执行等。 九、实战...

    韩顺平servlet部分的源码文件

    这两个方法是Servlet生命周期的一部分,当用户通过浏览器发送请求时,Servlet容器(如Tomcat)会调用相应的请求处理方法。 接着,我们来看源码文件中的关键点。韩顺平老师的源码可能会包含以下内容: 1. **Servlet...

    how tomcat work_中文版(源码)

    《如何让Tomcat工作:中文版(源码)》是一份深入探讨Web服务器Tomcat工作原理的资源,其中包含了详细的理论讲解以及配套的源码分析。这份资料旨在帮助读者理解Tomcat内部机制,从而能够更好地优化和调试应用程序。 ...

    servlet api 源码jar包 Mac版

    6. **源码分析**: 拥有源码jar包意味着你可以查看Servlet API的内部实现,理解其工作原理,这对于学习和优化代码非常有帮助。例如,你可以研究`HttpServletRequest`和`HttpServletResponse`是如何处理HTTP请求和...

    Servlet 介绍 以及Servlet生命周期(详细)

    Servlet是Java Web开发中的核心组件,它是一种...结合源码分析和适当的工具,如调试器和日志记录,可以更好地理解和优化Servlet的性能。在实际项目中,熟练运用Servlet能帮助开发者构建出功能强大、扩展性强的Web应用。

    servlet 源码

    源码分析对于深入理解Servlet的工作原理至关重要。在这个`servlet源码`的压缩包中,我们有`tomcat-6-src`,这包含了Apache Tomcat 6的源代码,一个流行的Servlet容器实现。 Apache Tomcat是一个开源的Web应用服务器...

Global site tag (gtag.js) - Google Analytics