7.Spring MVC处理请求的过程

本文详细解析了SpringMVC框架处理HTTP请求的过程,从Servlet容器接收请求开始,经过HttpServletBean、FrameworkServlet和DispatcherServlet等多个阶段,最终完成请求处理并响应给客户端。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       本文将分析Spring MVC是如何处理请求的;

       首先,分析HttpServletBean,FrameworkServlet和DispatcherServlet这三个Servlet的处理过程;这样大家就可以明白从Servlet容器将请求交给Spring MVC一直到DispatcherServlet具体处理请求之前都做了什么;

       最后再重点分析Spring MVC中最核心的处理方法doDispatch的处理流程;

HttpServletBean

       它主要参与了创建工作,并没有涉及到请求的处理;

FrameworkServlet

       Servlet的处理过程:首先从Servlet接口的service方法开始,然后在HttpServlet的service方法中根据请求的类型不同将请求路由到了doGet,doHead,doPost,doPut,doDelete,doOptions和doTrace这7个方法;

       HttpServlet默认实现了doHead,doOptions和doDelete;

       FrameworkServlet重写了service以及除了doHead的所有其他6个方法;

       在service方法中增加了对PATCH类型请求的处理,其他类型的请求直接交给父类进行处理;doOptions和doTrace方法可以通过设置dispatchOptionsRequest和dispatchTraceRequest参数决定是自己处理还是交给父类处理(默认是交给父类,doOptions会在父类的处理结果中增加PATCH类型);所有需要自己处理的请求都交给processRequest方法统一处理;

protected void service(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    String method = request.getMethod();
    
    //对PATCH类型请求的处理
    if (method.equalsIgnoreCase(RequestMethod.PATCH.name())) {
        processRequest(request, response);
    }
    else {
        super.service(request, response);
    }
}

protected final void doGet(HttpServletRequest request,HttpServletResponse response)
        throws ServletException,IOException {
    processRequest(request,response);   //别的需要自己处理的方法都与doGet类似
}

       这里的处理思路和HttpServlet的相反,它是将所有的请求都合并到了processRequest方法,不同类型的请求用不同的Handler进行处理;

       为什么要这样做呢,不再调用super.service(),而是直接将请求交给processRequest处理不是更简单吗?从结构上来看确实如此,但是如果这样做的话会存在一些问题;

     例如:我们为了某种特殊需求需要在Post请求处理前对request进行一些处理,这时可能会新建一个继承自DispatcherServlet的类,然后覆盖doPost方法,在里面对request进行处理,然后再调用super.doPost方法,但是父类根本没有调用doPost,这时就会出现问题,虽然有其他方法来解决这个问题,但按正常的逻辑,调用doPost应该可以完成才合理,而且一般情况下开发者并不需要对Spring MVC 的内部结构非常了解。所以Spring MVC的这种做法是有必要的;

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {

    long startTime = System.currentTimeMillis();
    Throwable failureCause = null;

    //获取LocaleContextHolder中原来保存的LocaleContext
    LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
    //获取当前请求的LocaleContext
    LocaleContext localeContext = buildLocaleContext(request);
    //获取RequestContextHolder中原来保存的RequestAttributes
    RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
    //获取当前请求的ServletRequestAttributes
    ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
    
    //将当前请求的LocaleContext和ServletRequestAttributes设置到LocaleContextHolder和RequestContextHolder中
    initContextHolders(request, localeContext, requestAttributes);

    try {
        //核心语句,这是一个模板方法,在DispatcherServlet中具体实现
        //在这之前和之后都做了一些事情,processRequest整个方法就是我们熟知的装饰模式
        doService(request, response);             /////////////////////////////////////////////////////
    }
    catch (ServletException ex) {
        failureCause = ex;
        throw ex;
    }
    catch (IOException ex) {
        failureCause = ex;
        throw ex;
    }
    catch (Throwable ex) {
        failureCause = ex;
        throw new NestedServletException("Request processing failed", ex);
    }
    finally {
        //恢复原来的LocaleContext和ServiceRequestAttributes到LocaleContextHolder和RequestContextHolder,
        //避免影响Servlet以外的处理,如Filter
        resetContextHolders(request, previousLocaleContext, previousAttributes);
        if (requestAttributes != null) {
            requestAttributes.requestCompleted();
        }

        if (l
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值