• springMVC源码 (3) DispatcherServlet处理请求


    前言

    DispatcherServlet继承httpServlet,所以实质上DispatcherServlet也是一个Servlet,这一点在DispatcherServlet初始化时就证明了。在tomcat执行某个servlet的时候,首先会调用service方法,然后在service方法中判断是哪一种请求方法,在分配到对应的请求方法处理函数去处理请求。在探究DispatcherServlet处理请求的过程,也会从service方法开始。

    DispatcherServlet请求处理过程

    service(HttpServletRequest request, HttpServletResponse response)方法

    	protected void service(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
    		HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
    		if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
    			processRequest(request, response);
    		}
    		else {
    			super.service(request, response);
    		}
    	}
    

    HttpMethod是一个枚举类,主要设置了请求的多种方式(post,get,head,put,patch等等),HttpMethod.resolve方法主要检查request的请求方法是其中的哪一种,如果都不是则返回null。这里我们一般是get,post,put,delete方法用的较多,所以执行else语句的时候较多。

    super.service(HttpServletRequest req, HttpServletResponse resp)方法

        protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
        {
            String method = req.getMethod();
            if (method.equals(METHOD_GET)) {
                long lastModified = getLastModified(req);
                if (lastModified == -1) {
                    doGet(req, resp);
                } else {
                    long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                    if (ifModifiedSince < lastModified) {
                        maybeSetLastModified(resp, lastModified);
                        doGet(req, resp);
                    } else {
                        resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                    }
                }
    
            } else if (method.equals(METHOD_HEAD)) {
                long lastModified = getLastModified(req);
                maybeSetLastModified(resp, lastModified);
                doHead(req, resp);
    
            } else if (method.equals(METHOD_POST)) {
                doPost(req, resp);
                
            } else if (method.equals(METHOD_PUT)) {
                doPut(req, resp);
                
            } else if (method.equals(METHOD_DELETE)) {
                doDelete(req, resp);
                
            }
                .....
        }
    

    可以看到super.service方法就是前言中所说的那样,根据请求方式的不同选择相对应的方法来处理。

    可以看到FrameworkServlet类中重写了Httpservlet中的各种处理对应请求方式的处理函数

    	protected final void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
    		processRequest(request, response);
    	}
    
    	@Override
    	protected final void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
    		processRequest(request, response);
    	}
    
    	@Override
    	protected final void doPut(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
    		processRequest(request, response);
    	}
    
    	
    	@Override
    	protected final void doDelete(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
    		processRequest(request, response);
    	}
    
    

    他们都调用统一个方法来处理

    processRequest(request, response)方法

      protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
                            .....
    			doService(request, response);
                            ....
    	}
    

    processRequest方法中比较重要的就是doService方法

    doService(HttpServletRequest request, HttpServletResponse response)方法

    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    		
    
    		// Keep a snapshot of the request attributes in case of an include,
    		// to be able to restore the original attributes after the include.
    		Map<String, Object> attributesSnapshot = null;
    		if (WebUtils.isIncludeRequest(request)) {
    			attributesSnapshot = new HashMap<>();
    			Enumeration<?> attrNames = request.getAttributeNames();
    			while (attrNames.hasMoreElements()) {
    				String attrName = (String) attrNames.nextElement();
    				if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
    					attributesSnapshot.put(attrName, request.getAttribute(attrName));
    				}
    			}
    		}
    
    		// Make framework objects available to handlers and view objects.
    		request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
    		request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
    		request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
    		request.setAttribute(THEME_SOURCE_ATTRIBUTE, 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 {
    			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);
    				}
    			}
    		}
    	}
    
    

    在doservice方法中也只是做了一些前期的准备工作,保存一些属性,在request中设置处理请求的工具(localeResolver,themeResolver),还有IOC容器。
    接着调用了doDispatch(request, response)方法。

    doDispatch(request, response)(重点)

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    		HttpServletRequest processedRequest = request;
    		HandlerExecutionChain mappedHandler = null;
    		boolean multipartRequestParsed = false;
    
    		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    
    		try {
    			ModelAndView mv = null;
    			Exception dispatchException = null;
    
    			try {
    				//  1.查看是否是 form表单上传参数 如果是将request包装成
    				processedRequest = checkMultipart(request);
    				multipartRequestParsed = (processedRequest != request);
    
    				//  2.获得handler----(这里的handler是指RequestMappingHandlerMapping,BeanNameUrlHandlerMapping等等)
    				mappedHandler = getHandler(processedRequest);
    				if (mappedHandler == null) {
                                             //如果没有找到对应的handler,则通过response.sendError(404);
    					noHandlerFound(processedRequest, response);
    					return;
    				}
    
    				//3.获得handlerAdapter
    				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
                                    //4.如果请求方法是 get/head  则查看处理请求的类或者方法是否发生改变
    				String method = request.getMethod();
    				boolean isGet = "GET".equals(method);
    				if (isGet || "HEAD".equals(method)) {
    					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
    					if (logger.isDebugEnabled()) {
    						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
    					}
    					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
    						return;
    					}
    				}
    
    				//  5.执行拦截器的preHandler方法
    				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    					return;
    				}
    
    				//6.执行处理请求的方法并得到ModeAndView
    				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
    				if (asyncManager.isConcurrentHandlingStarted()) {
    					return;
    				}
    				//7.在ModelAndView 不为空但是view = null 的时候   使用RequestToViewNameTranslator获得默认的view
    				applyDefaultViewName(processedRequest, mv);
    				//8.执行拦截器的postHandler方法
    				mappedHandler.applyPostHandle(processedRequest, response, mv);
    			}
    			catch (Exception ex) {
    				dispatchException = ex;
    			}
    			catch (Throwable err) {
    				// As of 4.3, we're processing Errors thrown from handler methods as well,
    				// making them available for @ExceptionHandler methods and other scenarios.
    				dispatchException = new NestedServletException("Handler dispatch failed", err);
    			}
                            //9.处理异常,解析View并执行view.render方法跳转页面
    			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    		}
    		catch (Exception ex) {
    			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    		}
    		catch (Throwable err) {
    			triggerAfterCompletion(processedRequest, response, mappedHandler,
    					new NestedServletException("Handler processing failed", err));
    		}
    		finally {
    			if (asyncManager.isConcurrentHandlingStarted()) {
    				// Instead of postHandle and afterCompletion
    				if (mappedHandler != null) {
    					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
    				}
    			}
    			else {
    				// Clean up any resources used by a multipart request.
    				if (multipartRequestParsed) {
    					cleanupMultipart(processedRequest);
    				}
    			}
    		}
    	}
    

    总结

    第一步:checkMultipart(request); 查看是否配置了MulqtipartResolver(MulqtipartResolver 组件在处理一个请求的时候不是必须的,所以在dispatcherServlet 初始化时并没有设置一个默认的MultipartResolver组件),如果配置了,则检测这个请求中是否上传了文件,如果是,则使用配置的MultipartResolver.resolveMultipart方法将request包装成一个MultipartHttpServletRequest,从这个对象中可以获得一个MultipartFile对象,然后获得文件的相关信息。

    第二步:获得一个HandlerMapping,用于找到请求url对应的处理类或者方法。如果没有找到对应的handlermapping,则返回404.

    第三步:获得一个HandlerAdapter,用于在执行处理方法前的一些预处理和执行处理方法。

    第四步:查看请求url对应的处理类或者方法是否发生过改变(通过last-modified),如果没有,则不需要处理该请求。如果发生了改变,则处理请求。

    第五步:执行interceptor的preHandle方法。

    第六步:通过handlerAdapter执行处理请求的方法并返回ModelAndView对象

    第七步:当返回的ModelAndView对象不为空但是没有view的时候,就获得defaultViewName。通过RequestToViewNameTranslator来解析request对象来获得。

    第八步:执行interceptor的postHandler方法

    第九步:处理方法执行后的结果。则其中包括这样几个步骤:

    1. 处理抛出的异常
      当抛出的异常是一个ModelAndViewDefiningException,直接调用其getModelAndView方法获得一个ModelAndView就行了。不是ModelAndViewDefiningException异常时,使用HandlerExceptionResolver来处理异常
    2. 处理View
      首先使用LocaleResolver来处理视图语言。
      然后使用ViewResolver来处理viewName,找到对应的View对象。
      执行View.render方法
    3. 执行interceptor的triggerAfterCompletion方法
  • 相关阅读:
    延迟加载时发生no session错误的解决办法
    零零散散的一些知识点(一)
    零零散散的一些知识点(二)
    自己写的一个日历表
    js复制网址
    load方法在延迟加载时可能出现的错误。
    JSON基本介绍
    JBOSS4.0 JDBC数据源配置大全
    EJB学习笔记一
    Android程序完全退出的方法
  • 原文地址:https://www.cnblogs.com/zhangchenwei/p/12583790.html
Copyright © 2020-2023  润新知