spring-mvc之请求响应执行流程

spring-mvc执行流程

spring-mvc之请求响应执行流程

注:Handler并不是具体的类或接口(实际上是Object),而是一个概念。
Controller是Handler的一种情况

Spring MVC采用了前端控制器模式(the front controller pattern),处于核心位置的DispatcherServlet调度其它组件完成对客户端的请求与响应。

1.用户请求发送到服务器,服务器,例如Tomcat创建并初始化httpServletRequesthttpServletResponse对象,交给DispatcherServlet进行管理

2.DispatcherServlet将请求委托给HandlerMapping进行处理,后者处理完毕后,会返回一个HandlerExecutionChain对象

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

这个对象包含一个Handler处理器(例如,Controller)对象和多个Handler拦截器(HandlerInterceptor)对象

3.DispatcherServlet从所有的Handler适配器中找到可以处理当前Handler的适配器(适配器模式)

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        for (HandlerAdapter adapter : this.handlerAdapters) {
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
    }
    throw new ServletException("No adapter for handler [" + handler +
            "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

4.获取到Handler适配器后,DispatcherServlet委托Handler适配器,执行Handler中的代码,返回ModelAndView对象

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    //...
    // Actually invoke the handler.
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    //...
}

5.得到了ModelAndView对象后,就可以开始渲染了

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
        @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
        @Nullable Exception exception) throws Exception {
        
        //...
        if (mv != null && !mv.wasCleared()) {
            render(mv, request, response);
            if (errorView) {
                WebUtils.clearErrorRequestAttributes(request);
            }
        }
        //...
}

首先,从ModelAndView对象中得到逻辑视图名

    protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
        //...
        View view;
        String viewName = mv.getViewName();
        if (viewName != null) {
            // We need to resolve the view name.
            view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
            if (view == null) {
                throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
                        "' in servlet with name '" + getServletName() + "'");
            }
        }
        //...
    }

然后,根据视图名,依次尝试可用的ViewResolver进行视图解析,如果成功,就返回View对象

@Nullable
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
        Locale locale, HttpServletRequest request) throws Exception {

    if (this.viewResolvers != null) {
        for (ViewResolver viewResolver : this.viewResolvers) {
            View view = viewResolver.resolveViewName(viewName, locale);
            if (view != null) {
                return view;
            }
        }
    }
    return null;
}

6.获取到View对象后,调用由模板引擎实现的的render()方法,将模型数据渲染到模板中

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    //...
    view.render(mv.getModelInternal(), request, response);
    //...
}

7.返回控制权给DispatcherServlet,由DispatcherServlet将响应(通过服务器)返回给用户

@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    //...
    try {
        doDispatch(request, response);
    }
    finally {
        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            // Restore the original attribute snapshot, in case of an include.
            if (attributesSnapshot != null) {
                restoreAttributesAfterInclude(request, attributesSnapshot);
            }
        }
        ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
    }
}
上一篇:批量移动文件(find和mv结合使用)


下一篇:Linux之mv命令