享读SpringMVC源码0--从Tomcat到SpringMVC

简介: 享读SpringMVC源码0--从Tomcat到SpringMVC

1.回顾


SpringMVC的核心是DispatcherServlet. 而DispatcherServlet的本质还是一个Servlet 。

说到Servlet 就得讲讲web服务器Tomcat。

文接Tomcat原理系列之三:请求链上的那些类Tomcat原理系列之七:详解socket如何封装成request(下)


2.请求从Tomcat到SpringMVC


请求通过Socket 开启应用之旅,在Tomcat原理系列之三:请求链上的那些类 中讲过,请求来到Tomcat的最后一个valve,StandardWrapperValve时。执行其invoke方法


image.png


StandardWrapperValve

请求来到StandardWrapperValve#invoke方法

final class StandardWrapperValve
    extends ValveBase {
    public final void invoke(Request request, Response response)
        throws IOException, ServletException {
        // 1.Allocate a servlet instance to process this request
        //分配一个servet 去处理请求
        servlet = wrapper.allocate();
        // 2.Create the filter chain for this request 
        //封装servlet, 为当前请求创建一个过滤器链
        ApplicationFilterChain filterChain =
                        ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
        //3.执行过滤器链的doFilter方法,(链式执行各种Filter ,末端执行servlet's service() method)
        filterChain.doFilter(request.getRequest(),
                                            response.getResponse());
        }
}


ApplicationFilterChain

之后来到 ApplicationFilterChain#doFilter方法

public final class ApplicationFilterChain implements FilterChain {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response)
            throws IOException, ServletException {
        internalDoFilter(request,response);//调用内部internalDoFilter方法
            }
     private void internalDoFilter(ServletRequest request,
                                      ServletResponse response)
            throws IOException, ServletException {
             // Call the next filter if there is one
             // 4.链式调用每个Filter的doFilter方法
             if (pos < n) {
                  filter.doFilter(request, response, this);
             }
             //5.调用servlet的service方法
             servlet.service(request, response);
            }
}

在Filter的末端,开始准备进入Servlet执行方法。


HttpServlet

我们来看看DispatcherServlet 的继承图

image.png


从图中我们可以看出,DispatcherServlet 通过几层父类间接实现Servlet。

ApplicationFilterChain中 调用servlet.service(request, response);传递的参数是(ServletRequest request, ServletResponse response)。所以执行的是HttpServlet 中的service方法.可以看出此方法的目的是将ServletRequest,ServletResponse 转换为我们熟悉的HttpServletRequest  ,HttpServletResponse


public abstract class HttpServlet extends GenericServlet {
 //6.执行HttpServlet.service()方法,做req,res 的强制转换
 public void service(ServletRequest req, ServletResponse res){
    HttpServletRequest  request;
    HttpServletResponse response;
    try {
        //转为 HttpServletRequest,HttpServletResponse
         request = (HttpServletRequest) req;
         response = (HttpServletResponse) res;
    } catch (ClassCastException e) {
                throw new ServletException("non-HTTP request or response");
    }
    service(request, response);
    }
 //8.执行HttpServlet.service此时的参数已经是HttpServletRequest,HttpServletResponse
 //并根据请求方法类型。调用不同的处理方法。子类FrameworkServlet 类中重写了一些方法,所以转去执行子类的doGet方法
 protected void service(HttpServletRequest req, HttpServletResponse resp)
         throws ServletException, IOException {
      if (method.equals(METHOD_GET)) {
        doGet(req, resp);   
      }
    }
 }


FrameworkServlet

public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
 //7.兼容PATCH方法,非PATCH方法最终还是交给HttpServlet.service()
 protected void service(HttpServletRequest request, HttpServletResponse response)
             throws ServletException, IOException {
         HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
         if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
             processRequest(request, response);
         }
         else {
             super.service(request, response);
         }
 }
//9.get代理方法,转到processRequset去处理
 protected final void doGet(HttpServletRequest request, HttpServletResponse response)
             throws ServletException, IOException {
         processRequest(request, response);
     }
//10.模板方法,请求的处理交给子类的doService方法去处理
 protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
             throws ServletException, IOException {
        doService(request, response);
     }
}


DispatcherServlet

最终请求来到了DispatcherServlet的doService方法,开始DispatcherServlet的工作内容

//最终来到了DispatcherServlet
public class DispatcherServlet extends FrameworkServlet {
    //11.做请求分发前的准备工作,主要是设置一些请求的相关属性
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        doDispatch(request, response);
    }
    //12 开启请求的分发。
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //开启DispatcherServlet的分发功能
    }
}

最终请求到了DispatcherServlet的doDispatch开启DispatcherServlet 请求分发处理功能。


3.DispatcherServlet的工作原理


请求到达doDispatch 方法后,DispatcherServlet对其做了什么呢?这就引出了DispatcherServlet的工作原理这个话题。


处理流程

借用网上张图:

image.png


  1. 请求来到DispatcherServlet
  2. DispatcherServlet根据请求信息,从HandlerMapping 找能处理当前请求的Handler并封装成一个HandlerExecutionChain
  3. 根据解析到的Handler ,获取一个适配器。
  4. HandlerAdapter会根据Handler来调用真正的处理器开处理请求,列如我们写的controller类中的业务方法
  5. 处理器处理完业务后,会返回一个ModelAndView对象,Model是返回的数据对象,View是个逻辑上的View
  6. ViewResolver会根据逻辑View查找实际的View。
  7. 视图渲染完成后,DispatcherServlet返回。

这些流程反映在代码中,就是doDispatch 方法内的相关调用了.

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        try {
            ModelAndView mv = null;
            Exception dispatchException = null;
            try {
                //检查是否是上传文件请求
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);
                // 获取能处理当前请求的Handler 链
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }
                // 获取能处理当前请求的的handler的适配器
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
                // Process last-modified header, if supported by the handler.
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (logger.isDebugEnabled()) {
                        logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                    }
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
                //拦截器前置处理
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
                //适配器handle方法处理请求。
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
                applyDefaultViewName(processedRequest, mv);
                //拦截器后置处理
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            catch (Throwable err) {
                dispatchException = new NestedServletException("Handler dispatch failed", err);
            }
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Throwable err) {
            triggerAfterCompletion(processedRequest, response, mappedHandler,
                    new NestedServletException("Handler processing failed", err));
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                // Instead of postHandle and afterCompletion
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                // Clean up any resources used by a multipart request.
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }


4.总结


我们可以看出,DispatcherServlet采用了“中心化”的思想。请求统一过DispatcherServlet,这样的好处就是统一管理。DispatcherServlet就有点路由的意思了。

本文衔接Tomcat原理系列之七:详解socket如何封装成request(下) 终于粗略的过了一遍,请求如何从socket经Tomcat到达DispatcherServlet,变成我们常用的HttpServletRequest 。对于web 的工作原理有了更深的理解


相关文章
|
3月前
|
XML 前端开发 Java
SpringMVC入门到实战------2、SpringMVC创建实例Hello SpringMVC(maven+tomcat)
这篇文章是SpringMVC框架的入门教程,详细指导了如何在IDEA中使用Maven和Tomcat创建SpringMVC工程,包括添加依赖、配置web.xml、编写控制器、创建配置文件、配置Tomcat服务器以及进行基本的测试,展示了一个简单的Hello SpringMVC示例。
SpringMVC入门到实战------2、SpringMVC创建实例Hello SpringMVC(maven+tomcat)
|
6月前
|
安全 Java 应用服务中间件
阿里技术官架构使用总结:Spring+MyBatis源码+Tomcat架构解析等
分享Java技术文以及学习经验也有一段时间了,实际上作为程序员,我们都清楚学习的重要性,毕竟时代在发展,互联网之下,稍有一些落后可能就会被淘汰掉,因此我们需要不断去审视自己,通过学习来让自己得到相应的提升。
|
存储 应用服务中间件 容器
springmvc-页面跳转&表单标签&其他标签&tomcat控制台中文乱码问题
springmvc-页面跳转&表单标签&其他标签&tomcat控制台中文乱码问题
|
6月前
|
Java 应用服务中间件 Spring
Spring5源码(50)-SpringMVC源码阅读环境搭建
Spring5源码(50)-SpringMVC源码阅读环境搭建
75 0
|
3月前
|
监控 网络协议 Java
Tomcat源码解析】整体架构组成及核心组件
Tomcat,原名Catalina,是一款优雅轻盈的Web服务器,自4.x版本起扩展了JSP、EL等功能,超越了单纯的Servlet容器范畴。Servlet是Sun公司为Java编程Web应用制定的规范,Tomcat作为Servlet容器,负责构建Request与Response对象,并执行业务逻辑。
Tomcat源码解析】整体架构组成及核心组件
|
3月前
|
缓存 Java 应用服务中间件
SpringMVC入门到实战------七、SpringMVC创建JSP页面的详细过程+配置模板+实现页面跳转+配置Tomcat。JSP和HTML配置模板的差异对比(二)
这篇文章详细介绍了在SpringMVC中创建JSP页面的全过程,包括项目的创建、配置、Tomcat的设置,以及如何实现页面跳转和配置模板解析器,最后还对比了JSP和HTML模板解析的差异。
SpringMVC入门到实战------七、SpringMVC创建JSP页面的详细过程+配置模板+实现页面跳转+配置Tomcat。JSP和HTML配置模板的差异对比(二)
|
3月前
|
前端开发 Java Spring
SpringMVC种通过追踪源码查看是哪种类型的视图渲染器(一般流程方法)
这篇文章通过示例代码展示了如何在Spring MVC中编写和注册拦截器,以及如何在拦截器的不同阶段添加业务逻辑。
SpringMVC种通过追踪源码查看是哪种类型的视图渲染器(一般流程方法)
|
5月前
|
前端开发 Java 应用服务中间件
Spring框架第六章(SpringMVC概括及基于JDK21与Tomcat10创建SpringMVC程序)
Spring框架第六章(SpringMVC概括及基于JDK21与Tomcat10创建SpringMVC程序)
|
6月前
|
前端开发 Java 关系型数据库
基于ssm框架旅游网旅游社交平台前后台管理系统(spring+springmvc+mybatis+maven+tomcat+html)
基于ssm框架旅游网旅游社交平台前后台管理系统(spring+springmvc+mybatis+maven+tomcat+html)
|
6月前
|
设计模式 算法 前端开发
Tomcat的源码剖析, 启动过程你会吗?
基于JMX Tomcat会为每个组件进行注册过程,通过Registry管理起来,而Registry是基于JMX来实现的,因此在看组件的init和start过程实际上就是初始化MBean和触发MBean的start方法,会大量看到形如: Registry.getRegistry(null, null).invoke(mbeans, "init", false); Registry.getRegistry(null, null).invoke(mbeans, "start", false); 这样的代码,这实际上就是通过JMX管理各种组件的行为和生命期。
36 0