SpringMVC处理请求整个链路原理

文章详细描述了SpringMVC中的请求处理流程,包括处理多语言、异步请求、文件上传、HandlerMapping/HandlerAdapter、拦截器的使用以及视图渲染的逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

protected final void processRequest(HttpServletRequest request, HttpServletResponse response){
	// 处理多言语问题
	LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
	LocaleContext localeContext = buildLocaleContext(request);
	// 创建RequestAttributes对象,整个请求通用,封装了请求和响应对象
	RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
	// 里面设置属性都是调用request对象设置属性,所以,整个请求需要获取request对象使用RequestContextHolder就能获取
	ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

	// 获取异步请求管理器
	WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
	// 添加一个拦截器,负责处理requestAttributes
	asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

	// 初始化RequestContextHolder,将requestAttributes保存到RequestContextHolder中
	initContextHolders(request, localeContext, requestAttributes);{
		if (requestAttributes != null) {
			RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
		}
	}
	// 处理请求
	doService(request, response);{
		// 把当前web容器和其他组件放入请求域中
		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());
		// flush管理器,用于重定向存储数据的管理器
		FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
		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);


        protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
            // 获取异步管理器
            WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
            // 校验是不是文件上传请求,如果是,返回新的request对象
            HttpServletRequest processedRequest = checkMultipart(request);{
                if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
                    // 使用文件解析器解析请求,返回新的request对象
                    return this.multipartResolver.resolveMultipart(request);
                }
            }
            // 找到的handler和拦截器封装成HandlerExecutionChain对象
            HandlerExecutionChain mappedHandler = getHandler(processedRequest);{
                // 从所有的HandlerMapping中找
                if (this.handlerMappings != null) {
                    for (HandlerMapping mapping : this.handlerMappings) {
                        HandlerExecutionChain handler = mapping.getHandler(request);{
                            // 获取对应的handler,具体的逻辑在对应的handlerMapping中,可以看HandlerMapping的获取Handler方法
                            Object handler = getHandlerInternal(request);
                            // 将handler封装成HandlerExecutionChain
                            HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);{
                                创建HandlerExecutionChain对象返回
                                HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
                                // 将存在HandlerMapping中的拦截器附加到Handler中,形成拦截器链
                                for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
                                     // 如果不是,直接添加
                                    if (!(interceptor instanceof MappedInterceptor) {
                                       chain.addInterceptor(interceptor);
                                       return chain;
                                    }
                                     // 如果是自定义,设置了条件的拦截器,要特殊处理下
                                    MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
                                    // 该拦截器还要匹配拦截当前请求
                                    if (mappedInterceptor.matches(request)) {
                                        chain.addInterceptor(mappedInterceptor.getInterceptor());
                                    }
                                }
                                return chain;
                            }
                        }
                        if (handler != null) {
                            return handler;
                        }
                    }
                }
            }
            // 未找到Handler,直接响应404
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);{
                    response.sendError(HttpServletResponse.SC_NOT_FOUND);
                }
                return;
            }
            // 查找handlerAdapter,HandlerAdapter才是真正执行业务逻辑的类
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());{
                // 遍历所有的HandlerAdapter
                if (this.handlerAdapters != null) {
                    for (HandlerAdapter adapter : this.handlerAdapters) {
                        if (adapter.supports(handler){
                                                    // 能处理请求的HandlerAdapter
                                                    return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
                                                    return handler instanceof HandlerFunction;
                                                    return (handler instanceof HttpRequestHandler);
                                                    return (handler instanceof Controller);
                                                    return (handler instanceof Servlet);
                                                }) {
                            return adapter;
                        }
                    }
                }
            }
            // 执行handler的前置方法
            if (!mappedHandler.applyPreHandle(processedRequest, response){
                // 遍历所有的拦截器,
                for (int i = 0; i < this.interceptorList.size(); i++) {
                    HandlerInterceptor interceptor = this.interceptorList.get(i);
                    // 执行拦截器的前置方法
                    if (!interceptor.preHandle(request, response, this.handler)) {
                        // 如果前置方法返回false
                        // 直接执行请求处理结束的方法
                        triggerAfterCompletion(request, response, null);
                        // 请求结束
                        return false;
                    }
                    this.interceptorIndex = i;
                }
                    // 当返回true表示所有的拦截器前置方法都返回了ture
                    return true;
                })
            {
            //  如果前置方法返回false,当前请求结束
                return;
            }

            // 执行目标方法,无论如何都会返回一个ModelAndView对象
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());{
                org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal{
                    // 校验请求是否可以处理
                    checkRequest(request);{
                        String method = request.getMethod();
                        // 如果设置了限制的请求方式,但是当前请求不符合规则
                        if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {
                            throw new HttpRequestMethodNotSupportedException(method, this.supportedMethods);
                        }
                        // 如果设置了请求必须要有session
                        if (this.requireSession && request.getSession(false) == null) {
                            throw new HttpSessionRequiredException("Pre-existing session required but none found");
                        }
                    }
                    // 如果同一个session需要同步执行,则需要对session加锁
                    if (this.synchronizeOnSession) {
                        HttpSession session = request.getSession(false);
                        if (session != null) {
                            // 使用session最为锁对象
                            Object mutex = WebUtils.getSessionMutex(session);
                            synchronized (mutex) {
                                // 加锁执行方法
                                ModelAndView mav = invokeHandlerMethod(request, response, handlerMethod);
                            }
                        }
                    }else{
                        // 不需要同步就直接执行目标方法,详请看笔记执行目标方法原理
                        ModelAndView mav = invokeHandlerMethod(request, response, handlerMethod);
                    }
                    // 如果当前请求不包含Cache-Control请求头,
                    if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
                        // 如果handlerMethod存在一些Session缓存,就需要缓存一些会话信息
                        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
                            applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);{
                                // 例如设置过期时间
                                if cacheSeconds>0  response.setDateHeader(HEADER_EXPIRES, System.currentTimeMillis() + seconds * 1000L);
                                else response.setHeader(HEADER_PRAGMA, "no-cache");
                            }
                        }
                        else {
                            // 预处理设置响应头
                            prepareResponse(response);{
                                // 根据不同条件设置
                                applyCacheControl(response, this.cacheControl);
                                applyCacheSeconds(response, this.cacheSeconds);
                                response.addHeader("Vary", value);
                            }
                        }
                    }
                    return mav;
                }
            }
            // 如果请求被异步启动了,就不处理了
            if (asyncManager.isConcurrentHandlingStarted()) {
            	return;
            }
            // 获取视图名,如果没有设置视图名,返回一个默认的视图名,就是url对应的字符串当做视图
            applyDefaultViewName(processedRequest, mv);{
                // 如果没有异常,并且modeAndView中没有设置视图
                // 在Controller的方法中,没有添加ResponseBody注解,也没有添加String返回值,也没有使用Response响应
                // 此时springmvc默认会返回一个空的modeAndView,符合这个条件
                // 例如: @GetMapping("haha") public void haha(HttpServletRequest req) {  req.setAttribute("luck", "luck");}
                // 视图名会被解析成haha,因为不管有没有返回值,都会返回一个ModelAndView
                // 大胆猜测,如果我的方法返回void,然后将设置属性到request,或者model中,然后SpringMVC会自动跳转到路径对应的jsp页面
                // 也就是haha.jsp中,这个时候,在jsp中${luck}是可以获取到值的
                if (mv != null && !mv.hasView()) {
                    // 获取一个默认的视图名,就是url对应的字符串当做视图
                    String defaultViewName = getDefaultViewName(request);
                    // 将这个当做是视图名,到时候找对应文件渲染
                    if (defaultViewName != null) {
                        mv.setViewName(defaultViewName);
                    }
                }
            }
            // 执行所有的拦截器后置处理
            mappedHandler.applyPostHandle(processedRequest, response, mv);

            catch (Exception ex) Exception dispatchException = ex;
            catch (Throwable err) Exception dispatchException = new NestedServletException("Handler dispatch failed", err);;

            // 处理相应结果,视图渲染,包括正常渲染和异常渲染
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);{
                boolean errorView = false;
                // 判断是否有异常,如果有异常,就要构造异常的modeAndView,如果没有异常,那就直接渲染
                if (exception != null) {
                	// 返回异常为ModelAndViewDefiningException,返回此异常的ModeAndView
                	if (exception instanceof ModelAndViewDefiningException) {
                		mv = ((ModelAndViewDefiningException) exception).getModelAndView();
                	}
                	// 如果是其他类型的异常
                	else {
                		// 获取处理请求的handler
                		Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
                		// 构建一个异常的ModeAndView,处理异常
                		mv = processHandlerException(request, response, handler, exception);{
                			request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
                			// 如果存在异常解析器
                			if (this.handlerExceptionResolvers != null) {
                				// 遍历所有的异常解析器解析异常
                				for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
                					// 使用异常解析器解析异常,详情见异常解析器处理加载处理原理
                					ModelAndView exMv = resolver.resolveException(request, response, handler, ex);
                					if (exMv != null) {
                						break;
                					}
                				}
                			}
                			// 解析到异常的ModelAndView对象
                			if (exMv != null) {
                				// 如果这个ModelAndView是一个空的对象,也就是不包含响应视图等等,返回空
                				// exMv.isEmpty 源码 return (this.view == null && CollectionUtils.isEmpty(this.model));
                				// 表示当前view为空,并且Model modelMap也为空
                				if (exMv.isEmpty()) {
                					request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
                					return null;
                				}
                				// 如果View为空的情况下,但是Model modelMap不为空的情况下,会使用路径作为默认的视图界面
                				// 因为model中有数据,可以直接将model中的数据传递都页面中,详情见上面的applyDefaultViewName(processedRequest, mv);方法
                				// 例如: @GetMapping("haha") public void haha(HttpServletRequest req) {  req.setAttribute("luck", "luck");}
                                // 视图名会被解析成haha,因为不管有没有返回值,都会返回一个ModelAndView
                                // 大胆猜测,如果我的方法返回void,然后将设置属性到request,或者model中,然后SpringMVC会自动跳转到路径对应的jsp页面
                                // 也就是haha.jsp中,这个时候,在jsp中${luck}是可以获取到值的
                                // 例如:  @ExceptionHandler(NullPointerException.class) public void e(Model model) {model.addAttribute("luck", "luck");}
                				if (!exMv.hasView()) {
                					// 获取默认的View的视图名
                					String defaultViewName = getDefaultViewName(request);
                					// 如果设置了视图名,那么就要按正常的视图渲染流程
                					if (defaultViewName != null) {
                						exMv.setViewName(defaultViewName);
                					}
                				}
                				// 将一个异常相关的属性数据存入request域中
                				WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
                				return exMv;
                			}
                		}
                		// 异常视图标志
                		errorView = (mv != null);
                	}
                }

                // modeAndView的wasCleared默认为false,除非手动调用了mv.clear
                if (mv != null && !mv.wasCleared()) {
                	// 会进入视图渲染,详情见视图渲染原理
                	render(mv, request, response);
                	// 如果处理了异常的情况下,请求放在请求域中的异常数据都清除
                	if (errorView) {
                		WebUtils.clearErrorRequestAttributes(request);
                	}
                }

                // 如果是异步请求,直接结束,不执行下面的拦截器后置方法
                if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
                	return;
                }
                // 找到了handler,执行拦截器的后置方法
                if (mappedHandler != null) {
                	mappedHandler.triggerAfterCompletion(request, response, null);
                }
            }

            // 整个请求结束,无论如何到需要执行拦截器的afterCompletion方法
            catch (Exception ex) triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
            catch (Throwable err) triggerAfterCompletion(processedRequest, response, mappedHandler,new NestedServletException("Handler processing failed", err));

            // doDispatch执行结束,如果是文件上传,需要删除临时文件
            finally if (multipartRequestParsed) cleanupMultipart(processedRequest);{
                if (this.multipartResolver != null) {
                    // 调用文件解析器,清理文件,因为文件上传之前,会创建临时文件在磁盘中,请求处理完成要删除
                    this.multipartResolver.cleanupMultipart(multipartRequest);
                }
            }
        }
	}
	// 重置requestAttributes
	resetContextHolders(request, previousLocaleContext, previousAttributes);
	if (requestAttributes != null) {
		requestAttributes.requestCompleted();
	}
	// 发布事件
	publishRequestHandledEvent(request, response, startTime, failureCause);
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值