SpringMVC源码分析(四)请求流程分析

编程入门 行业动态 更新时间:2024-10-13 08:25:50

SpringMVC<a href=https://www.elefans.com/category/jswz/34/1770099.html style=源码分析(四)请求流程分析"/>

SpringMVC源码分析(四)请求流程分析

a、http请求是怎么被Controller接受处理,然后返回结果的?

发出HTTP请求后,跳过网络层的东西,当被应用服务器Tomcat接受的时候。在Tomcat中存在一个servlet容器,它负责管理所有的servlet,包括SpringMVC的核心组件DispatcherServlet。
请求进入到HttpServlet的service方法中后。service方法会根据 HTTP 请求是 GET、POST、PUT 还是 DELETE 等,进一步调用 Servlet 的 doGet(),doPost(),doPut(),doDelete() 等方法。
1、HttpServlet# service()
2、FrameworkServlet# doGet() 或 doPost() 或 doPut() 或 doDelete()
3、FrameworkServlet# processRequest()


1、HttpServlet#service()

HttpServletRequest 和 HttpServletResponse 对象是由 Servlet 容器(Tomcat)在调用 Servlet 的 service() 方法之前创建和初始化的。
最终所有的请求都会走到FrameworkServlet的processRequest()中

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) {// servlet doesn't support if-modified-since, no reason// to go through further expensive logicdoGet(req, resp);} else {long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);if (ifModifiedSince < lastModified) {// If the servlet mod time is later, call doGet()// Round down to the nearest second for a proper compare// A ifModifiedSince of -1 will always be lessmaybeSetLastModified(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);} else if (method.equals(METHOD_OPTIONS)) {doOptions(req,resp);} else if (method.equals(METHOD_TRACE)) {doTrace(req,resp);} else {//// Note that this means NO servlet supports whatever// method was requested, anywhere on this server.//String errMsg = lStrings.getString("http.method_not_implemented");Object[] errArgs = new Object[1];errArgs[0] = method;errMsg = MessageFormat.format(errMsg, errArgs);resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);}}

1.2 FrameworkServlet#doPost()

1.2 FrameworkServlet#doGet()

1.2 FrameworkServlet#doPut()

1.2 FrameworkServlet#doDelete()

@Overrideprotected final void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {processRequest(request, response);}/*** Delegate POST requests to {@link #processRequest}.* @see #doService*/@Overrideprotected final void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {processRequest(request, response);}/*** Delegate PUT requests to {@link #processRequest}.* @see #doService*/@Overrideprotected final void doPut(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {processRequest(request, response);}/*** Delegate DELETE requests to {@link #processRequest}.* @see #doService*/@Overrideprotected final void doDelete(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {processRequest(request, response);}

1.3 FrameworkServlet# processRequest()

在processRequest(request, response)方法中,主要执行了如下步骤:
【1】获得当前和最新request中的国际化上下文LocaleContext;
【2】获得当前和最新request中的请求参数RequestAttributes;
【3】初始化异步请求管理器WebAsyncManager;
【4】将最新request中的“国际化上下文”和“请求参数”设置到当前线程的上下文中,在整个doService共享,在finally后删除。
【5】doService()处理Http请求;
【6】将当前线程上下文中的“国际化上下文”和“请求参数”还原为之前的值;
【7】无论成功与否,都会发布ServletRequestHandledEvent事件;

protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {long startTime = System.currentTimeMillis();Throwable failureCause = null;// 针对【国际化上下文】,获得当前的LocaleContext和最新request请求中的LocaleContextLocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); LocaleContext localeContext = buildLocaleContext(request);// 针对【请求参数】,获得当前的RequestAttributes和最新request请求中的RequestAttributesRequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);// 初始化【异步请求管理器】WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());// 将request中最新的“国际化上下文”和“请求参数”设置到当前线程的上下文中initContextHolders(request, localeContext, requestAttributes);try {/** 处理请求 */doService(request, response); }catch (ServletException | IOException ex) {...}catch (Throwable ex) {...}finally {// 还原以前的国际化上下文和请求参数设置到当前线程的上下文中resetContextHolders(request, previousLocaleContext, previousAttributes);if (requestAttributes != null) requestAttributes.requestCompleted();// 无论成功与否,都会发布ServletRequestHandledEvent事件publishRequestHandledEvent(request, response, startTime, failureCause);}
}

2、doService(request, response)

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {Map<String, Object> attributesSnapshot = null;/** 在include请求时保存请求属性的快照,以便在include请求后恢复原始属性 */if (WebUtils.isIncludeRequest(request)) { // 确定给定的请求是否是一个include请求(判断方法:request中是否存在“javax.servlet.include.request_uri”的属性参数)attributesSnapshot = new HashMap<>();Enumeration<?> attrNames = request.getAttributeNames();while (attrNames.hasMoreElements()) {String attrName = (String) attrNames.nextElement();// DEFAULT_STRATEGIES_PREFIX="org.springframework.web.servlet"if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) attributesSnapshot.put(attrName, request.getAttribute(attrName));}}/** 设置request属性 */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);}RequestPath previousRequestPath = null;if (this.parseRequestPath) {previousRequestPath = (RequestPath) request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);ServletRequestPathUtils.parseAndCache(request); // request.setAttribute(PATH_ATTRIBUTE, requestPath);}/** 处理Http请求 */try {doDispatch(request, response);}finally {if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {if (attributesSnapshot != null) restoreAttributesAfterInclude(request, attributesSnapshot); // include请求后恢复原始属性}if (this.parseRequestPath) ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request); // 还原请求参数中PATH_ATTRIBUTE的值}
}

3、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 {//如果是Multipart请求,则将request转换为MultipartHttpServletRequest类型 */processedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);/**根据request,寻找匹配的Handler */mappedHandler = getHandler(processedRequest);if (mappedHandler == null) {noHandlerFound(processedRequest, response); // 如果没找到,则抛出异常或者返回404return;}/**根据Handler,寻找匹配的HandlerAdapter */HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());String method = request.getMethod();boolean isGet = HttpMethod.GET.matches(method);if (isGet || HttpMethod.HEAD.matches(method)) {long lastModified = ha.getLastModified(request, mappedHandler.getHandler());if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) return;}/**调用已注册的拦截器列表interceptors的preHandle方法 */if (!mappedHandler.applyPreHandle(processedRequest, response)) return;/**处理请求的逻辑并返回ModelAndView */mv = ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) return;//如果没有视图View,则向mv中设置默认的视图名称applyDefaultViewName(processedRequest, mv);//调用已注册的拦截器列表interceptors的postHandle方法mappedHandler.applyPostHandle(processedRequest, response, mv);}catch (Exception ex) {//	省略代码}catch (Throwable err) {//省略代码}/**调用handler以及处理返回的结果,该结果要么是ModelAndView,要么就是一个需要解析到ModelAndView的异常 */processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}catch (Exception ex) {//省略代码}catch (Throwable err) {//省略代码}finally {//省略代码}
}

3.1 getHandler(request)

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {/** 2.1.1 试图从request请求中获取handler实例 **/Object handler = getHandlerInternal(request);if (handler == null) handler = getDefaultHandler(); // 如果获取不到,则获取默认handler,if (handler == null) return null; // 如果仍然获取不到,则直接返回null// 如果上面获取到的header是字符串类型的beanName,则从IOC中获取到对应的beanif (handler instanceof String) {String handlerName = (String) handler;handler = obtainApplicationContext().getBean(handlerName);}// 确保拦截器等的缓存查找路径(lookupPath)的存在if (!ServletRequestPathUtils.hasCachedPath(request)) initLookupPath(request);/** 2.1.2 将配置中对应的拦截器加入到执行链中,以确保拦截器生效 */HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);// 针对CORS(跨域)请求,进行特殊处理if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {CorsConfiguration config = getCorsConfiguration(handler, request);if (getCorsConfigurationSource() != null) {CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);config = (globalConfig != null ? globalConfigbine(config) : config);}if (config != null) {config.validateAllowCredentials();}executionChain = getCorsHandlerExecutionChain(request, executionChain, config);}return executionChain;
}

3.1.1 getHandlerInternal(request)

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);try {return super.getHandlerInternal(request); // 调用AbstractHandlerMethodMapping的getHandlerInternal方法}finally {ProducesRequestCondition.clearMediaTypesAttribute(request);}
}
> AbstractHandlerMethodMapping#getHandlerInternal(request)
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {/**【步骤1】从request中寻找请求路径 */String lookupPath = initLookupPath(request); // eg: lookupPath="/hello"this.mappingRegistry.acquireReadLock();try {/**【步骤2】通过lookupPath和request,获得请求待流转的方法handlerMethod */HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);}finally {this.mappingRegistry.releaseReadLock();}
}

3.1.2、initLookupPath()

// eg: lookupPath="/hello"
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {List<Match> matches = new ArrayList<>();/**【步骤1】根据请求路径lookupPath来获得可以匹配处理的方法列表  */List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);/**【步骤2】从directPathMatches获取匹配的Match实例对象,并保存到matches集合中 */if (directPathMatches != null) // 根据request对象,解析出http请求method、参数params,请求headers等信息来创建RequestMappingInfo对象,// 然后封装到Match对象中,并保存到matches中 addMatchingMappings(directPathMatches, matches, request);if (matches.isEmpty()) addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);/**【步骤3】针对已匹配的Match集合对象进行处理 */if (!matches.isEmpty()) {Match bestMatch = matches.get(0);// 发现匹配上了两个相同的method,则进行特殊处理或者抛出异常if (matches.size() > 1) {Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));matches.sort(comparator);bestMatch = matches.get(0);if (CorsUtils.isPreFlightRequest(request)) for (Match match : matches) if (match.hasCorsConfig()) return PREFLIGHT_AMBIGUOUS_MATCH;    else {Match secondBestMatch = matches.get(1);if (comparatorpare(bestMatch, secondBestMatch) == 0) {Method m1 = bestMatch.getHandlerMethod().getMethod();Method m2 = secondBestMatch.getHandlerMethod().getMethod();String uri = request.getRequestURI();throw new IllegalStateException("Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");}}}// eg: bestMatch.getHandlerMethod()=com.muse.springbootdemo.controller.DemoController#hello()request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());handleMatch(bestMatch.mapping, lookupPath, request); // 对request进行附加属性赋值return bestMatch.getHandlerMethod(); // 返回com.muse.springbootdemo.controller.DemoController#hello()}/**【步骤4】没有找到已匹配的Match集合对象,则进行异常抛出等操作 */else return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
}
> getMappingsByDirectPath()
// eg:urlPath="/hello"
public List<T> getMappingsByDirectPath(String urlPath) {return this.pathLookup.get(urlPath); // eg:return {GET [/hello]}
}

3.1.3、getHandlerExecutionChain(handler, request)

【Object handler】真正处理请求的headler;
【List interceptorList】interceptor拦截器列表;

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {//【步骤1】要么强转HandlerExecutionChain类型,要么新建HandlerExecutionChain实例对象HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));//【步骤2】遍历adaptedInterceptors,将符合条件的拦截器加入到chain中for (HandlerInterceptor interceptor : this.adaptedInterceptors) {if (interceptor instanceof MappedInterceptor) {MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;if (mappedInterceptor.matches(request)) chain.addInterceptor(mappedInterceptor.getInterceptor());}else chain.addInterceptor(interceptor);}return chain;
}

实现一个自定义的请求拦截器时,可以通过实现HandlerInterceptor接口的方式,这个接口一共有3个方法,分别是针对处理请求之前进行拦截操作的preHandle方法,以及针对处理请求之后进行拦截操作的postHandle方法,和在所有请求处理完毕之后进行额外操作afterCompletion方法,代码如下所示:

public interface HandlerInterceptor {// 在处理请求之前进行额外操作default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return true;}// 在处理请求之后进行额外操作default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable ModelAndView modelAndView) throws Exception {}// 在所有请求处理完毕之后进行额外操作default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable Exception ex) throws Exception {}}

3.2 getHandlerAdapter(request)

我们会通过逐一遍历根据handlerAdapters集合,通过调用HandlerAdapter的supports(handler)方法,来获取与入参handler相匹配的HandlerAdapter,只要找到了匹配的HandlerAdapter,直接返回即可,不再继续遍历对比.
handlerAdapters默认包含4个HandlerAdapter,分别是:
RequestMappingHandlerAdapter
HandlerFunctionAdapter
HttpRequestHandlerAdapter
SimpleControllerHandlerAdapter

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {if (this.handlerAdapters != null) for (HandlerAdapter adapter : this.handlerAdapters) if (adapter.supports(handler)) // 寻找到匹配的adapterreturn adapter; // eg: RequestMappingHandlerAdapter@7511// 如果没有找到HandlerAdapter,则抛出异常throw new ServletException(...);
}

HandlerAdapter接口

public interface HandlerAdapter {// 是否匹配该HandlerAdapterboolean supports(Object handler);// 处理请求,返回结果ModelAndViewModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;// 用于请求缓存,已作废@Deprecatedlong getLastModified(HttpServletRequest request, Object handler);
}

3.3 handle()

public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return handleInternal(request, response, (HandlerMethod) handler);
}

3.3.1 handleInternal()

在该方法中,主要是执行了两个步骤:
【步骤1】调用invokeHandlerMethod(request, response, handlerMethod)方法真正的执行请求处理;
【步骤2】对于Header不包含 “Cache-Control”的情况进行特殊处理。

protected ModelAndView handleInternal(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {ModelAndView mav;checkRequest(request);// Execute invokeHandlerMethod in synchronized block if required.if (this.synchronizeOnSession) {HttpSession session = request.getSession(false);if (session != null) {Object mutex = WebUtils.getSessionMutex(session);synchronized (mutex) {mav = invokeHandlerMethod(request, response, handlerMethod);}}else {// No HttpSession available -> no mutex necessarymav = invokeHandlerMethod(request, response, handlerMethod);}}else {// No synchronization on session demanded at all...mav = invokeHandlerMethod(request, response, handlerMethod);}if (!response.containsHeader(HEADER_CACHE_CONTROL)) {if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);}else {prepareResponse(response);}}return mav;}
3.3.1.1 invokeHandlerMethod()

【1】进行实例对象的创建及赋值操作,包含:webRequest、binderFactory、modelFactory、invocableMethod、……
【2】通过invocableMethod.invokeAndHandle(webRequest, mavContainer)方法,进行请求处理;
【3】通过getModelAndView(mavContainer, modelFactory, webRequest)方法,将执行结果封装为ModelAndView实例对象;

protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response,HandlerMethod handlerMethod) throws Exception {// 创建webRequestServletWebRequest webRequest = new ServletWebRequest(request, response);try {// 创建binderFactory和modelFactoryWebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);//  创建及设置invocableMethodServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);if (this.argumentResolvers != null) invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);if (this.returnValueHandlers != null) invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);invocableMethod.setDataBinderFactory(binderFactory);invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);// 创建及设置mavContainerModelAndViewContainer mavContainer = new ModelAndViewContainer();mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));modelFactory.initModel(webRequest, mavContainer, invocableMethod);mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);// 创建及设置asyncWebRequestAsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);asyncWebRequest.setTimeout(this.asyncRequestTimeout);// 创建及设置asyncManagerWebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);asyncManager.setTaskExecutor(this.taskExecutor);asyncManager.setAsyncWebRequest(asyncWebRequest);asyncManager.registerCallableInterceptors(this.callableInterceptors);asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);if (asyncManager.hasConcurrentResult()) {Object result = asyncManager.getConcurrentResult();mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];asyncManager.clearConcurrentResult();invocableMethod = invocableMethod.wrapConcurrentResult(result);}/** 处理请求,实际执行逻辑的地方 */invocableMethod.invokeAndHandle(webRequest, mavContainer);if (asyncManager.isConcurrentHandlingStarted()) return null;// 处理请求返回结果,获得ModelAndViewreturn getModelAndView(mavContainer, modelFactory, webRequest);}finally {webRequest.requestCompleted();}
}
1 invokeAndHandle()
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {/** 通过反射请求到具体的Controller上,并获得返回值 */Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);// 根据ResponseStatus注释设置响应状态setResponseStatus(webRequest);// 如果没有返回值if (returnValue == null) {if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {disableContentCachingIfNecessary(webRequest);mavContainer.setRequestHandled(true);return;}}// 如果存在返回相关的响应状态原因else if (StringUtils.hasText(getResponseStatusReason())) {mavContainer.setRequestHandled(true);return;}mavContainer.setRequestHandled(false);/** 针对利用HandlerMethodReturnValueHandler的handleReturnValue方法,对返回值进行处理 */try {this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer,  webRequest);} catch (Exception ex) {throw ex;}
}/*** 根据ResponseStatus注释设置响应状态*/
private void setResponseStatus(ServletWebRequest webRequest) throws IOException {// 获得请求响应状态,如果为null,则直接返回HttpStatus status = getResponseStatus();if (status == null) return;// 获得请求响应response,尝试为response设置失败信息(response.sendError)或者状态码(response.setStatus)HttpServletResponse response = webRequest.getResponse();if (response != null) {String reason = getResponseStatusReason();if (StringUtils.hasText(reason)) response.sendError(status.value(), reason);else response.setStatus(status.value());}// 被RedirectView获取webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status);
}
>>>>>> invokeForRequest()

对request请求中的参数进行解析,转换为方法的入参args,然后再采用反射的方式调用Controller类的所对应的处理方法,获得最终处理后的结果:

public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {/** 解析出请求的入参 **/Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);/** 利用反射,调用Controller类的所对应的处理方法 */return doInvoke(args);
}/*** 请求参数解析*/
protected Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {// 获得http请求中的参数列表,如果没有入参,则直接返回空的入参数组MethodParameter[] parameters = getMethodParameters();if (ObjectUtils.isEmpty(parameters)) return EMPTY_ARGS;Object[] args = new Object[parameters.length];for (int i = 0; i < parameters.length; i++) {MethodParameter parameter = parameters[i];parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);// 如果参数属于providedArgs类型,则跳过,不进行解析args[i] = findProvidedArgument(parameter, providedArgs);if (args[i] != null) continue;/** 如果所有resolver解析器都不能解析的话,则直接抛出异常 */if (!this.resolvers.supportsParameter(parameter)) throw new IllegalStateException(...);/** 进行参数解析操作 */try {args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);} catch (Exception ex) {throw ex;}}return args;
}/*** 通过反射,执行逻辑调用*/
protected Object doInvoke(Object... args) throws Exception {// 获得被桥接的方法,即:用户自定义的方法Method method = getBridgedMethod();try {if (KotlinDetector.isSuspendingFunction(method)) return CoroutinesUtils.invokeSuspendingFunction(method, getBean(), args);// 利用反射,调用Controller类中相应的method方法return method.invoke(getBean(), args);}catch (IllegalArgumentException ex) {...}catch (InvocationTargetException ex) {...}
}
>>>>>>> supportsParameter(parameter)

该方法主要确定这个入参我们的解析器是否支持解析

public boolean supportsParameter(MethodParameter parameter) {// 获取方法参数解析器return getArgumentResolver(parameter) != null;
}
>>>>>>> resolveArgument()

在这个方法会依次遍历每个解析器的 supportsParameter(parameter) 方法来寻找可以解析入参parameter的具体解析器实现类resolver,如果找到了主要判断parameter参数是否有解析器可以对其进行解析;

public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {//【步骤1】获取方法参数解析器HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);if (resolver == null) throw new IllegalArgumentException("Unsupported parameter type ...");//【步骤2】执行解析操作return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
>>>>>>>> getArgumentResolver() 获取入参解析器

RequestParamMethodArgumentResolver:负责处理@RequestParam
RequestHeaderMethodArgumentResolver:负责处理@RequestHeader
SessionAttributeMethodArgumentResolver:负责处理@SessionAttribute
RequestAttributeMethodArgumentResolver:负责处理@RequestAttribute
RequestResponseBodyMethodProcessor:负责处理@RequestBody

/*** 获得可以解析parameter参数的方法参数解析器(HandlerMethodArgumentResolver)*/
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {// 如果之前解析过,则直接从缓存中获取HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);if (result == null) {for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {if (resolver.supportsParameter(parameter)) { // supportsParameter方法是由子类实现的result = resolver;this.argumentResolverCache.put(parameter, result); // 保存到缓存中break;}}}return result; 
}
>>>>>> handleReturnValue()

主要寻找可以对结果进行处理的handler实例对象;然后调用handler的handleReturnValue()方法来进行结果的处理。
HandlerMethodReturnValueHandler来处理返回值:
RequestResponseBodyMethodProcessor:处理加了@ResponseBody注解的情况
ViewNameMethodReturnValueHandler:处理没有加@ResponseBody注解并且返回值类型为String的情况
ModelMethodProcessor:处理返回值是Model类型的情况
…等等其他得默认的一些处理器

public void handleReturnValue(Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {/** 选择可以对结果进行解析的解析器 */HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);if (handler == null) throw new IllegalArgumentException("Unknown return value type: " + ...);/** 具体解析操作,由子类负责 */handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}/** * 选择可以对结果进行解析的解析器*/
private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {boolean isAsyncValue = isAsyncReturnValue(value, returnType);for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) continue;if (handler.supportsReturnType(returnType)) // 由子类负责实现supportsReturnType方法return handler;}return null;
}
>>>>>>>>>>RequestResponseBodyMethodProcessor#handleReturnValue()

RequestResponseBodyMethodProcessor会处理加了@ResponseBody注解的情况,也是常用的一种。会直接方法返回的结果直接响应给浏览器,返回的结果可能是字符串 ;可能是对象; 可能是Map或者其他形式的。

@ResponseBody
public String test() {return "张三";
}
>------------------>默认的4个MessageConverter

SpringMVC会利用HttpMessageConverter来处理;

  1. ByteArrayHttpMessageConverter:处理返回值为字节数组的情况,把字节数组返回给浏览器
  2. StringHttpMessageConverter:处理返回值为字符串的情况,把字符串按指定的编码序列号后返回给浏览器
protected void writeInternal(String str, HttpOutputMessage outputMessage) throws IOException {HttpHeaders headers = outputMessage.getHeaders();if (this.writeAcceptCharset && headers.get(HttpHeaders.ACCEPT_CHARSET) == null) {headers.setAcceptCharset(getAcceptedCharsets());}Charset charset = getContentTypeCharset(headers.getContentType());StreamUtils.copy(str, charset, outputMessage.getBody());
}
  1. SourceHttpMessageConverter:处理返回值为XML对象的情况,比如把DOMSource对象返回给浏览器
  2. AllEncompassingFormHttpMessageConverter:处理返回值为MultiValueMap对象的情况
>------------------>特殊的MappingJackson2HttpMessageConverter

MappingJackson2HttpMessageConverter,这个Converter比较强大,能把String、Map、User对象等等都能转化成JSON格式。

@EnableWebMvc
public class AppConfig implements WebMvcConfigurer {@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();messageConverter.setDefaultCharset(StandardCharsets.UTF_8);converters.add(messageConverter);}
}
@Overridepublic void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest)throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {mavContainer.setRequestHandled(true);ServletServerHttpRequest inputMessage = createInputMessage(webRequest);ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);// Try even with null return value. ResponseBodyAdvice could get involved.writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);}

3.4 processDispatchResult()

private void processDispatchResult(HttpServletRequest request,HttpServletResponse response,HandlerExecutionChain mappedHandler, ModelAndView mv,Exception exception) throws Exception {boolean errorView = false;//【步骤1】如果出现了异常,则进行异常处理if (exception != null) {if (exception instanceof ModelAndViewDefiningException) mv = ((ModelAndViewDefiningException) exception).getModelAndView();else {Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);mv = processHandlerException(request, response, handler, exception);errorView = (mv != null);}}//【步骤2】如果存在mv,则对mv进行渲染操作if (mv != null && !mv.wasCleared()) {render(mv, request, response); /** 执行页面渲染操作 */if (errorView) WebUtils.clearErrorRequestAttributes(request);}if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) return;if (mappedHandler != null) mappedHandler.triggerAfterCompletion(request, response, null);
}

3.4.1 processHandlerException(request, response, handler, exception)

具体流程见异常处理描述

protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,@Nullable Object handler, Exception ex) throws Exception {// Success and error responses may use different content typesrequest.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);// Check registered HandlerExceptionResolvers...ModelAndView exMv = null;if (this.handlerExceptionResolvers != null) {for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {exMv = resolver.resolveException(request, response, handler, ex);if (exMv != null) {break;}}}if (exMv != null) {if (exMv.isEmpty()) {request.setAttribute(EXCEPTION_ATTRIBUTE, ex);return null;}// We might still need view name translation for a plain error model...if (!exMv.hasView()) {String defaultViewName = getDefaultViewName(request);if (defaultViewName != null) {exMv.setViewName(defaultViewName);}}if (logger.isTraceEnabled()) {logger.trace("Using resolved error view: " + exMv, ex);}else if (logger.isDebugEnabled()) {logger.debug("Using resolved error view: " + exMv);}WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());return exMv;}throw ex;}
@Override@Nullablepublic ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {if (shouldApplyTo(request, handler)) {prepareResponse(ex, response);ModelAndView result = doResolveException(request, response, handler, ex);if (result != null) {// Print debug message when warn logger is not enabled.if (logger.isDebugEnabled() && (this.warnLogger == null || !this.warnLogger.isWarnEnabled())) {logger.debug("Resolved [" + ex + "]" + (result.isEmpty() ? "" : " to " + result));}// Explicitly configured warn logger in logException method.logException(ex, request);}return result;}else {return null;}}

3.4.2 render(mv, request, response)

尝试获得View实例对象;然后对view对象页面渲染

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {// Determine locale for request and apply it to the response.Locale locale =(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());response.setLocale(locale);View view;String viewName = mv.getViewName();if (viewName != null) {// We need to resolve the view name.view = resolveViewName(viewName, mv.getModelInternal(), locale, request);if (view == null) {throw new ServletException("Could not resolve view with name '" + mv.getViewName() +"' in servlet with name '" + getServletName() + "'");}}else {// No need to lookup: the ModelAndView object contains the actual View object.view = mv.getView();if (view == null) {throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +"View object in servlet with name '" + getServletName() + "'");}}// Delegate to the View object for rendering.if (logger.isTraceEnabled()) {logger.trace("Rendering view [" + view + "] ");}try {if (mv.getStatus() != null) {response.setStatus(mv.getStatus().value());}view.render(mv.getModelInternal(), request, response);}catch (Exception ex) {if (logger.isDebugEnabled()) {logger.debug("Error rendering view [" + view + "]", ex);}throw ex;}}
3.4.2.1 resolveViewName()

通过resolveViewName()来创建view视图对象,并将其加入到IOC中,其具体实现方式还是遍历每一个视图解析器(ViewResolver),调用其resolverViewName(viewName, locale)方法,尝试获得View视图实例对象,如果获得到了,则直接返回,不需要继续遍历其他的视图解析器了

protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,Locale locale, HttpServletRequest request) throws Exception {if (this.viewResolvers != null) {for (ViewResolver viewResolver : this.viewResolvers) {View view = viewResolver.resolveViewName(viewName, locale);if (view != null) {return view;}}}return null;}

@Override@Nullablepublic View resolveViewName(String viewName, Locale locale) throws Exception {if (!isCache()) {return createView(viewName, locale);}else {Object cacheKey = getCacheKey(viewName, locale);View view = this.viewAccessCache.get(cacheKey);if (view == null) {synchronized (this.viewCreationCache) {view = this.viewCreationCache.get(cacheKey);if (view == null) {// Ask the subclass to create the View object.view = createView(viewName, locale);if (view == null && this.cacheUnresolved) {view = UNRESOLVED_VIEW;}if (view != null) {this.viewAccessCache.put(cacheKey, view);this.viewCreationCache.put(cacheKey, view);}}}}else {if (logger.isTraceEnabled()) {logger.trace(formatKey(cacheKey) + "served from cache");}}return (view != UNRESOLVED_VIEW ? view : null);}}
createView()

最终创建视图是通过loadView()

@Nullableprotected View createView(String viewName, Locale locale) throws Exception {return loadView(viewName, locale);}@Overrideprotected View loadView(String viewName, Locale locale) throws Exception {AbstractUrlBasedView view = buildView(viewName);View result = applyLifecycleMethods(viewName, view);return (view.checkResource(locale) ? result : null);}
loadView()->buildView(viewName)
protected AbstractUrlBasedView buildView(String viewName) throws Exception {Class<?> viewClass = getViewClass();Assert.state(viewClass != null, "No view class");AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(viewClass);view.setUrl(getPrefix() + viewName + getSuffix());String contentType = getContentType();if (contentType != null) {view.setContentType(contentType);}view.setRequestContextAttribute(getRequestContextAttribute());view.setAttributesMap(getAttributesMap());Boolean exposePathVariables = getExposePathVariables();if (exposePathVariables != null) {view.setExposePathVariables(exposePathVariables);}Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes();if (exposeContextBeansAsAttributes != null) {view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes);}String[] exposedContextBeanNames = getExposedContextBeanNames();if (exposedContextBeanNames != null) {view.setExposedContextBeanNames(exposedContextBeanNames);}return view;}
loadView()->applyLifecycleMethods(viewName, view)

initializeBean() ioc的知识了

protected View applyLifecycleMethods(String viewName, AbstractUrlBasedView view) {ApplicationContext context = getApplicationContext();if (context != null) {Object initialized = context.getAutowireCapableBeanFactory().initializeBean(view, viewName);if (initialized instanceof View) {return (View) initialized;}}return view;}
3.4.2.2 view.render(mv.getModelInternal(), request, response)
@Overridepublic void render(@Nullable Map<String, ?> model, HttpServletRequest request,HttpServletResponse response) throws Exception {if (logger.isDebugEnabled()) {logger.debug("View " + formatViewName() +", model " + (model != null ? model : Collections.emptyMap()) +(this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes));}Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);/** 渲染前的准备操作(可由子类自定义实现)*/prepareResponse(request, response);/** 将渲染后的视图合并到输出流中(可由子类自定义实现)*/renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);}
1 prepareResponse()
/*** 试图View被渲染前的准备操作*/
protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) {setResponseContentType(request, response); // 设置response响应的ContentTyperesponse.setCharacterEncoding(this.encoding.getJavaName()); // 设置response响应的CharacterEncodingif (this.disableCaching) response.addHeader("Cache-Control", "no-store"); // 设置response响应的Cache-Control
}
2 renderMergedOutputModel()
/*** 将渲染后的视图合并到输出流中*/
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {ByteArrayOutputStream temporaryStream = null;OutputStream stream;//【步骤1】获得相应的输出流if (this.updateContentLength) {temporaryStream = createTemporaryOutputStream();stream = temporaryStream;}else stream = response.getOutputStream();//【步骤2】试图serializationView和filters包装在MappingJacksonValue实例对象中Object value = filterAndWrapModel(model, request);//【步骤3】将渲染的视图value保存到输出流stream中writeContent(stream, value);if (temporaryStream != null) writeToResponse(response, temporaryStream);
}

3、总结流程图

更多推荐

SpringMVC源码分析(四)请求流程分析

本文发布于:2023-12-08 12:42:35,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1672825.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:源码   流程   SpringMVC

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!