SpringMVC执行流程

15 篇文章 1 订阅

目录

一、SpringMVC常用组件

1.DispatcherServlet

2.HandlerMapping

3.Handler

4.HandlerAdapter

5.ViewResolver

6.View

二、DispatcherServlet初始化过程

⚪FrameworkServlet 中的initServletBean方法(源码)

initServletBean中initWebApplicationContext 源码(创建IOC容器)

initWebApplicationContext中的onRefresh方法(源码) 

DispatcherServlet中重写的 onRefresh方法(源码) 

DispatcherServlet的初始化策略initStrategies (源码) 

三、DispatcherServlet调用组件处理请求

⚪HttpServlet中对service方法进行了重写&重载​编辑

⚪FrameWorkServlet中的service 

四、SpringMVC的执行流程


一、SpringMVC常用组件

1.DispatcherServlet

前端控制器,不需要工程师开发,由框架提供

作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求

2.HandlerMapping

处理器映射器,不需要工程师开发,由框架提供

作用:根据请求的url、method等信息查找Handler,即控制器方法

3.Handler

处理器,需要工程师开发

作用:在DispatcherServlet的控制下Handler对具体的用户请求进行处理

4.HandlerAdapter

处理器适配器,不需要工程师开发,由框架提供

作用:通过HandlerAdapter对处理器(控制器方法)进行执行

5.ViewResolver

视图解析器,不需要工程师开发,由框架提供

作用:进行视图解析,得到相应的视图,例如:ThymeleafView、InternalResourceView、 RedirectView

6.View

视图

作用:将模型数据通过页面展示给用户

二、DispatcherServlet初始化过程

DispatcherServlet 本质上是一个 Servlet,所以天然的遵循 Servlet 的生命周期。

因此宏观上是 Servlet 生命周期来进行调度。

public final void init() throws ServletException {
    PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
    if (!pvs.isEmpty()) {
        try {
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());
            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
            this.initBeanWrapper(bw);
            bw.setPropertyValues(pvs, true);
        } catch (BeansException var4) {
            if (this.logger.isErrorEnabled()) {
                this.logger.error("Failed to set bean properties on servlet '" + this.getServletName() + "'", var4);
            }
            throw var4;
        }
    }
    this.initServletBean();
}
protected void initServletBean() throws ServletException {
}

⚪FrameworkServlet 中的initServletBean方法(源码)

protected final void initServletBean() throws ServletException {
    this.getServletContext().log("Initializing Spring " + 
    this.getClass().getSimpleName() + 
    " '" + 
    this.getServletName() + 
    "'");
    if (this.logger.isInfoEnabled()) {
        this.logger.info("Initializing Servlet '" + 
        this.getServletName() + "'");
    }
    long startTime = System.currentTimeMillis();
    try {
        //初始化SpringMVC的IOC容器
        this.webApplicationContext = this.initWebApplicationContext();
        this.initFrameworkServlet();
    } catch (RuntimeException | ServletException var4) {
        this.logger.error("Context initialization failed", var4);
        throw var4;
    }
    if (this.logger.isDebugEnabled()) {
        String value = this.enableLoggingRequestDetails ? 
        "shown which may lead to unsafe logging of potentially sensitive data" : 
        "masked to prevent unsafe logging of potentially sensitive data";
        this.logger.debug("enableLoggingRequestDetails='" + 
        this.enableLoggingRequestDetails + 
        "': request parameters and headers will be " + 
        value);
    }
    if (this.logger.isInfoEnabled()) {
        this.logger.info("Completed initialization in " + 
        (System.currentTimeMillis() - startTime) + " ms");
    }
}

initServletBean中initWebApplicationContext 源码(创建IOC容器)

protected WebApplicationContext initWebApplicationContext() {
    WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
    WebApplicationContext wac = null;
    if (this.webApplicationContext != null) {
        wac = this.webApplicationContext;
        if (wac instanceof ConfigurableWebApplicationContext) {
            ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)wac;
            if (!cwac.isActive()) {
                if (cwac.getParent() == null) {
                   //设置当前SpringMVC的IOC容器的父容器
                    cwac.setParent(rootContext);
                }
                this.configureAndRefreshWebApplicationContext(cwac);
            }
        }
    }
    if (wac == null) {
        wac = this.findWebApplicationContext();
    }
    if (wac == null) {
        //创建IOC容器
        wac = this.createWebApplicationContext(rootContext);
    }
    if (!this.refreshEventReceived) {
        synchronized(this.onRefreshMonitor) {
            //刷新容器
            this.onRefresh(wac);
        }
    }
    if (this.publishContext) {
        String attrName = this.getServletContextAttributeName();
        //把SpringMVC容器共享到最大的域对象中
        this.getServletContext().setAttribute(attrName, wac);
    }
    return wac;
}

initWebApplicationContext中的onRefresh方法(源码) 

protected void onRefresh(ApplicationContext context) {
}

DispatcherServlet中重写的 onRefresh方法(源码) 

protected void onRefresh(ApplicationContext context) {
    //初始化策略
    this.initStrategies(context);
}

DispatcherServlet的初始化策略initStrategies (源码) 

protected void initStrategies(ApplicationContext context) {
    this.initMultipartResolver(context);//初始化文件上传解析器
    this.initLocaleResolver(context);  //初始化本地解析器
    this.initThemeResolver(context);
    this.initHandlerMappings(context); //初始化处理器映射器,处理请求映射
    this.initHandlerAdapters(context); //初始化处理适配器,调用控制器方法
    this.initHandlerExceptionResolvers(context);  //初始化异常解析器
    this.initRequestToViewNameTranslator(context);
    this.initViewResolvers(context);  //初始化视图解析器
    this.initFlashMapManager(context);
}

三、DispatcherServlet调用组件处理请求

⚪HttpServlet中对service方法进行了重写&重载

重写的service

根据请求方式的不用调用不同的方法

protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String CRLF = "\r\n";
    StringBuilder buffer = (new StringBuilder("TRACE ")).append(req.getRequestURI()).append(" ").append(req.getProtocol())
    Enumeration reqHeaderEnum = req.getHeaderNames();
    while(reqHeaderEnum.hasMoreElements()) {
        String headerName = (String)reqHeaderEnum.nextElement();
        buffer.append(CRLF).append(headerName).append(": ").append(req.getHeader(headerName));
    }
    buffer.append(CRLF);
    int responseLength = buffer.length();
    resp.setContentType("message/http");
    resp.setContentLength(responseLength);
    ServletOutputStream out = resp.getOutputStream();
    out.print(buffer.toString());
}
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String method = req.getMethod();
    long lastModified;
    if (method.equals("GET")) {
        lastModified = this.getLastModified(req);
        if (lastModified == -1L) {
            this.doGet(req, resp);
        } else {
            long ifModifiedSince = req.getDateHeader("If-Modified-Since");
            if (ifModifiedSince < lastModified) {
                this.maybeSetLastModified(resp, lastModified);
                this.doGet(req, resp);
            } else {
                resp.setStatus(304);
            }
        }
    } else if (method.equals("HEAD")) {
        lastModified = this.getLastModified(req);
        this.maybeSetLastModified(resp, lastModified);
        this.doHead(req, resp);
    } else if (method.equals("POST")) {
        this.doPost(req, resp);
    } else if (method.equals("PUT")) {
        this.doPut(req, resp);
    } else if (method.equals("DELETE")) {
        this.doDelete(req, resp);
    } else if (method.equals("OPTIONS")) {
        this.doOptions(req, resp);
    } else if (method.equals("TRACE")) {
        this.doTrace(req, resp);
    } else {
        String errMsg = lStrings.getString("http.method_not_implemented");
        Object[] errArgs = new Object[]{method};
        errMsg = MessageFormat.format(errMsg, errArgs);
        resp.sendError(501, errMsg);
    }
}

重载的service

public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
    if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) {
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)res;
        this.service(request, response);
    } else {
        throw new ServletException("non-HTTP request or response");
    }
}

⚪FrameWorkServlet中的service 

protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
    if (httpMethod != HttpMethod.PATCH && httpMethod != null) {
        super.service(request, response);//调用HttpServlet中的方法
    } else {
        this.processRequest(request, response);
    }
}

FrameWorkServlet将以下方法都进行了重写 

 

protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    this.processRequest(request, response);
}
protected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    this.processRequest(request, response);
}
protected final void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    this.processRequest(request, response);
}
protected final void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    this.processRequest(request, response);
}
protected void doOptions(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    if (this.dispatchOptionsRequest || CorsUtils.isPreFlightRequest(request)) {
        this.processRequest(request, response);
        if (response.containsHeader("Allow")) {
            return;
        }
    }
    super.doOptions(request, new HttpServletResponseWrapper(response) {
        public void setHeader(String name, String value) {
            if ("Allow".equals(name)) {
                value = (StringUtils.hasLength(value) ? value + ", " : "") + HttpMethod.PATCH.name();
            }
            super.setHeader(name, value);
        }
    });
}
protected void doTrace(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    if (this.dispatchTraceRequest) {
        this.processRequest(request, response);
        if ("message/http".equals(response.getContentType())) {
            return;
        }
    }
    super.doTrace(request, response);
}
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());
    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);
    }
}

四、SpringMVC的执行流程

1) 用户向服务器发送请求,请求被SpringMVC 前端控制器 DispatcherServlet捕获。

2) DispatcherServlet对请求URL(统一资源定位符)进行解析,得到请求资源标识符(URI),判断请求URI对应的映射:

不存在

  • 判断是否配置了  mvc:default-servlet-handler
  • 如果没配置,则控制台报映射查找不到,客户端展示404错误
  • 如果有配置,则访问目标资源(一般为静态资源,如:JS,CSS,HTML),找不到客户端也会展示404 错误

存在则执行下面的流程

3) 根据该URI,调用HandlerMapping(处理器映射器)获得该Handler配置的所有相关的对象(包括Handler对象以及 Handler对象对应的拦截器),最后以HandlerExecutionChain执行链对象的形式返回。

4) DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter(处理器适配器)

5) 如果成功获得HandlerAdapter,此时将开始执行拦截器的preHandler(…)方法【正向】

6) 提取Request中的模型数据(请求报文),填充Handler入参,开始执行Handler(Controller)方法,处理请求。 在填充Handler的入参过程中,根据配置,Spring将帮你做一些额外的工作:

  • HttpMessageConveter(报文信息转换器): 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
  • 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
  • 数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
  • 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中

7) Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象。

8) 此时将开始执行拦截器的postHandle(...)方法【逆向】

9) 根据返回的ModelAndView(此时会判断是否存在异常:如果存在异常,则执行 HandlerExceptionResolver进行异常处理)选择一个适合的ViewResolver进行视图解析,根据Model (向域对象共享数据)和View,来渲染视图。

10) 渲染视图完毕执行拦截器的afterCompletion(…)方法【逆向】

11) 将渲染结果返回给客户端。 

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

elk-zhang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值