SpringMvc请求处理流程与源码探秘

简介: SpringMvc请求处理流程与源码探秘流程梳理dispatcherServlet作为前端控制器的主要作用就是接受请求与处理响应。不过它不是传统意义上的servlet,它在接受到请求后采用转发的方式,将具体工作交给专业人士去做。

SpringMvc请求处理流程与源码探秘
流程梳理
dispatcherServlet作为前端控制器的主要作用就是接受请求与处理响应。

不过它不是传统意义上的servlet,它在接受到请求后采用转发的方式,将具体工作交给专业人士去做。

参与角色主要有:

前端控制器(DispatcherServlet)

处理映射器(HandlerMapping)

处理适配器(HandlerAdapter)

处理器((Handler)Controller)

视图解析器(ViewReslover)

视图(View)

找了一张图,把请求过程与步骤清晰的呈现了出来

第一步:前端控制器dispatcher接受请求

Client---url--->Dispatcher

第二步:前端控制器去发起handler映射查找请求

Dispatcher---HttpServletRequest---> HandlerMapping

第三步:处理器映射器查找hanlder并返回HandlerExetuionChain

 Dispatcher <---HandlerExeutionChain---HandlerMapping

第四步:前端控制器发起请求处理器适配器请求执行

Dispatcher---Handler---> HandlerAdapter

第五步:处理器适配器去调用handler执行

HandlerAdapter---HttpServletRequest> Handler(Controller)

第六步:处理器处理后返回ModelAndView给HandlerAdapter

HandlerAdapter <---ModelAndView---Handler(Controller)

第七步:处理器适配器将ModelAndView返回给前端控制器

Dispatcher <---ModelAndView---HandlerAdapter

第八步:前端控制器请求视图解析器解析ModelAndView

Dispatcher---ModelAndView---> ViewReslover

第九步:视图解析器解析视图后返回视图View给前端控制器

Dispatcher <---View---ViewReslover

第十步:前端控制器请求视图要求渲染视图

Dispatcher--->View--->render

第十一步:前端控制器返回响应

Response <---Dispatcher

源码探秘
第一步接受请求:
我们可以来看看DispatcherServlet的继承结构

其实DispatcherServlet能处理请求是因为HttpServlet类的service方法,而HttpServlet又来自Servlet接口定义的规范。

可以看到抽象类HttpServlet实现了接口Servlet的service方法,根据请求类型不同执行了不同的方法(doGet,doPost)

当请进来后,由HttpServlet的子类FrameworkServlet重写的service方法执行请求,可以看到437行子类调用了父类的service方法,然后在父类执行doGet之类的方法时,由于子类FrameworkServlet重写了父类方法,交由子类执行,所以进到了我的doGet断点里面,它调用了处理请求方法。

接下来我们看看ProcessRequest方法的源码

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

    long startTime = System.currentTimeMillis();
    Throwable failureCause = null;
    LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
    LocaleContext localeContext = this.buildLocaleContext(request);
    RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
    ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor(null));
    this.initContextHolders(request, localeContext, requestAttributes);

    try {
        this.doService(request, response);
    } catch (IOException | ServletException var16) {
        failureCause = var16;
        throw var16;
    } catch (Throwable var17) {
        failureCause = var17;
        throw new NestedServletException("Request processing failed", var17);
    } finally {
        this.resetContextHolders(request, previousLocaleContext, previousAttributes);
        if (requestAttributes != null) {
            requestAttributes.requestCompleted();
        }

        this.logResult(request, response, (Throwable)failureCause, asyncManager);
        this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
    }

}

前面一系列初始化工作我们先不管,看看重要的部分,try里面的doService方法

跟踪进去看了一下,由于它是抽象方法,所以会由子类实现和执行,也就是我们的DispatchServlet类了

老规矩,先贴上源码,它是DispatchServlet的doService方法--------------------------------------------------------------------------------------------------------------

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {

    this.logRequest(request);
    Map<String, Object> attributesSnapshot = null;
    if (WebUtils.isIncludeRequest(request)) {
        attributesSnapshot = new HashMap();
        Enumeration attrNames = request.getAttributeNames();

        label95:
        while(true) {
            String attrName;
            do {
                if (!attrNames.hasMoreElements()) {
                    break label95;
                }

                attrName = (String)attrNames.nextElement();
            } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));

            attributesSnapshot.put(attrName, request.getAttribute(attrName));
        }
    }

    request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
    request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
    request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
    request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
    if (this.flashMapManager != null) {
        FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
        if (inputFlashMap != null) {
            request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
        }

        request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
        request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
    }

    try {
        this.doDispatch(request, response);
    } finally {
        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
            this.restoreAttributesAfterInclude(request, attributesSnapshot);
        }

    }

}

所以第一步也就完成了,第一步的任务就是走进这里来。

第二步:前端控制器去发起handler映射查找请求
Dispatcher---HttpServletRequest---> HandlerMapping

上面的源码中主要工作就是给request实例设置一系列参数,要注意的就是doDispatch方法,这里面就是mvc的核心了,前面第一张交互图里面的流程都是在这里实现的。

可以看到,通过HttpRequestServlet作为参数请求handlerMapping

第三步:处理器映射器查找hanlder并返回HandlerExetuionChain

 Dispatcher <---HandlerExeutionChain---HandlerMapping

可以看到上图中返回了mappedHandler变量,就是HandlerExtuceChain类型

可以看到,已经找到并返回了我们的HomeController处理器(Hanlder)

第四步:前端控制器发起请求处理器适配器请求执行
Dispatcher---Handler---> HandlerAdapter

从508行可以看到,适配器传入handler对象和reaquest等信息,执行handler()方法

第五步:处理器适配器去调用handler执行
HandlerAdapter---HttpServletRequest> Handler(Controller)

从这里可以看到,调用的handlerInternal是个抽象方法,会调用子类的实现方法,子类由RequestMappingHandlerAdapter实现,这个类也是我们经常在xml里面配置的类

通过invokeHandlerMethod方法执行进到controller里面

方法执行后返回我们的index

第六步:处理器处理后返回ModelAndView给HandlerAdapter
HandlerAdapter <---ModelAndView---Handler(Controller)

通过调用invokeHandlerMethod方法返回ModelAndView

第七步:处理器适配器将ModelAndView返回给前端控制器
Dispatcher <---ModelAndView---HandlerAdapter

第八步:前端控制器请求视图解析器解析ModelAndView
Dispatcher---ModelAndView---> ViewReslover

第九步:视图解析器解析视图后返回视图View给前端控制器
Dispatcher <---View---ViewReslover

可以看到,返回的视图,url指向index.jsp页面

第十步:前端控制器请求视图要求渲染视图
Dispatcher--->View--->render

如果View对象不为空,将会调用render方法渲染

如果返回的是json对象,属于接口的,是不会走这里的

此时会找对应的视图解析器去渲染

里面其实也没干啥,就做了个跳转,到jsp页面去绑定数据

第十一步:前端控制器返回响应
Response <---Dispatcher

到这里也就基本上完了。

处理请求完成后做了个重置工作,然后发布一个事件,你可以选择监听这个事件,做相应处理。

再看看response里面

这个就是我们页面上的内容了。
原文地址https://www.cnblogs.com/jingch/p/10567394.html

相关文章
|
5月前
|
存储 前端开发 Java
SpringMVC中重定向请求时传输参数原理分析与实践
SpringMVC中重定向请求时传输参数原理分析与实践
98 2
SpringMVC中重定向请求时传输参数原理分析与实践
|
6月前
|
前端开发 应用服务中间件
SpringMVC 文件上传 消息 Required request part ‘file‘ is not present描述 由于被认为是客户端对错误(例如:畸形的请求语法、无效的请求信息帧或者
SpringMVC 文件上传 消息 Required request part ‘file‘ is not present描述 由于被认为是客户端对错误(例如:畸形的请求语法、无效的请求信息帧或者
330 0
|
8月前
|
设计模式 前端开发 JavaScript
【SpringMVC】工作流程及入门案例
【SpringMVC】工作流程及入门案例
24 0
|
7月前
|
JSON 前端开发 Java
springmvc-controller&视图层配置&SpringMVC处理请求的流程
springmvc-controller&视图层配置&SpringMVC处理请求的流程
|
5月前
|
JSON 数据格式
SpringMVC-接收请求中的json数据及日期类型参数传递
SpringMVC-接收请求中的json数据及日期类型参数传递
52 0
|
15天前
|
前端开发 Java 定位技术
生活小事件(SpringMVC主要的组件及作用和执行流程)
Spring MVC 的主要组件包括 DispatcherServlet(核心,请求调度)、HandlerMapping(URL 映射到处理器)、HandlerAdapter(统一执行处理器)、Handler(处理业务逻辑,通常为 @Controller 类)、ViewResolver(视图解析)和 View(渲染输出)。通过这些组件的协作,Spring MVC 实现了从接收请求到返回响应的流程,类似于警察处理交通违规的协调过程。
|
6月前
|
Java Spring
SpringMVC中请求传输的各种类型参数分析
SpringMVC中请求传输的各种类型参数分析
28 0
|
6月前
|
JSON 数据格式 容器
SpringMVC运行流程分析之核心流程
SpringMVC运行流程分析之核心流程
17 0
|
4月前
|
前端开发 Java 应用服务中间件
SpringMvc拦截器和手写模拟SpringMvc工作流程源码详解
MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分。 M: Model,模型层,指工程中的JavaBean,作用是处理数据。 JavaBean分为两类: 1.实体类Bean:专门存储业务数据的,如Student User等 2.业务处理Bean:指Service或Dao对象,专门用于处理业务逻辑和数据访问。
|
4月前
|
设计模式 前端开发 开发者
SpringMVC底层负责请求路由的模块是什么
SpringMVC底层负责请求路由的模块是什么
82 0