• springMVC执行流程详解


    一,springMVC执行流程

    1,MVC架构的由来

    主要由model层,view层和controller层组成。

    1.1,jsp模型

    主要是结构简单,开发这个小型项目的效率高,主要是由这个jsp和javaBean组成。但是jsp同时负责了controller层和view层,因此所有的代码都写在这个jsp里面,导致这个代码的重用性很低,维护不方便,因此这种架构被淘汰。

    1.2,servlet模型

    对上一个模型进行了一次改良,将这个controller层和view层进行了这个分离,让每个部分各司其职。请求由controller控制器完成,jsp就是专门用来展示数据,提高了代码可重用性和易维护性。
    在这里插入图片描述

    2,springMVC执行流程

    在这里插入图片描述

    1,客户端发送请求到这个DispatcherServlet前端控制器

    2,前端控制器会通过这个HandlerMapping处理器映射器,找到合适的处理器,就是通过这个输入的url,找到对应的handler

    3,返回处理器的执行链,里面会包含多个拦截器的信息,以及需要查找的处理器handler的信息

    4,找处理器适配器HandlerAdapter,这一步开始就会去调用handler里面的方法

    5,通过执行这个handler里面的方法,会去找具体的controller方法

    6,找到具体的controller之后,会返回一个modelAndView给这个HanderAdapter给处理器适配器

    7,处理器适配器获取到ModelAndView之后,会将这个结果返回给DispatcherServlet前端控制器

    8,通过这个ViewResolver视图解析器进行解析这个ModelAndView

    9,解析完成之后,会将这个view返回给前端DispatcherServlet前端控制器

    10,将model中的数据填充到这个view视图里面,最后去渲染视图

    二,源码分析

    1,首先打开这个DispatcherServlet类,可以发现这个类是继承了FrameworkServlet

    public class DispatcherServlet extends FrameworkServlet{...}
    
    • 1

    2,这个类里面有一个doService方法,里面有一个比较重要的方法,叫doDispatch方法

    doDispatch(request, response);
    
    • 1

    3,进入这个**doDispatch()**方法里面,可以看到以下几行代码,主要是来返回这个处理器执行链,处理器适配器等操作。

    //处理器执行链
    HandlerExecutionChain mappedHandler = null;
    //检测当前请求是否需要做文件上传
    processedRequest = checkMultipart(request);
    //获取需要的映射器以及拦截器等
    mappedHandler = getHandler(processedRequest);
    if (mappedHandler == null) {
    	noHandlerFound(processedRequest, response);
    	return;
    }
    //找这个处理器适配器
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    //调用拦截器 
    mappedHandler.applyPreHandle(processedRequest, response);
    //适配器开始调用这个handler
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    //处理这个结果集
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4,接下来所有的分析都基于这个**doDispatch()**方法,来对里面的方法做一个具体的描述。
    接下来看看这个getHandler方法,主要是通过这个request请求,来获取对应handler。

    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    	if (this.handlerMappings != null) {
            //遍历全部获取到的处理器映射器
    		for (HandlerMapping hm : this.handlerMappings) {
                //通过这个请求进行匹配,找到这个handler
    			HandlerExecutionChain handler = hm.getHandler(request);
                //找到则返回
    			if (handler != null) {
    				return handler;
    			}
            }
    	}
    	return null;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    5,接下来看看这个获取处理器适配器getHandlerAdapter的方法,适配器也有多种,会根据不同的handler适配不同的适配器。

    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    	if (this.handlerAdapters != null) {
    		for (HandlerAdapter ha : this.handlerAdapters) {
    			if (ha.supports(handler)) {
    				return ha;
    			}
    		}
    	}
    	throw new ServletException();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    6,再看这个doDispatch方法中的handle方法,可以点进去发现具体的实现如下。最终会以一个controller的对象返回

    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    	//以一个controller的方式返回    
    	return ((Controller) handler).handleRequest(request, response);
    }
    
    • 1
    • 2
    • 3
    • 4

    7,可以自定义重写这个handleRequest方法,最后以一个ModelAndView的格式返回给这个处理适配器,处理器适配器将这个ModelAndView返回给前端控制器。

    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
    	ModelAndView mv = new ModelAndView();
    	mv.setViewName("success");
    	mv.addObject("hello","zhs");
    	return mv;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    8,接下来看看这个前端控制器处理这个ModelAndView的视图解析,主要是通过这个processDispatchResult方法来实现。

    if (mv != null && !mv.wasCleared()) {
        //如果这个modelAndView不为空,就会开始进入正式的解析
    	render(mv, request, response);
    	if (errorView) {
    		WebUtils.clearErrorRequestAttributes(request);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    再进入这个render方法里面,可以发现这个视图解析器会对这个视图进行一个具体的解析,并且会将解析的view返回给这个DispatcherServlet里面,最终会将这个数据进行一个转发或者重定向,对这个view进行一个渲染,最终响应到这个客户端。

    //会进行一个具体的解析
    view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
    //解析
    view.render(mv.getModelInternal(), request, response);
    //输出
    renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
    //对这个获取的数据进行转发或者重定向
    RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    ETH开源PPO算法学习
    springboot 项目部署到Linux 服务器
    OpenAI与微软合作,构建 ChatGPT 5 模型;10天准确天气预报
    MyBatis核心对象简介说明
    Javascript专项练习
    SpringBoot整合dubbo(二)
    【网页设计】web前端期末大作业html+css
    Redis面试题一(基本概念)
    Spring的创建与使用
    day16_List&Set课后练习题 - 参考答案
  • 原文地址:https://blog.csdn.net/zhenghuishengq/article/details/126274702