| 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 { |
| processedRequest = checkMultipart(request); |
| multipartRequestParsed = (processedRequest != request); |
| |
| |
| |
| mappedHandler = getHandler(processedRequest); |
| if (mappedHandler == null) { |
| noHandlerFound(processedRequest, response); |
| return; |
| } |
| |
| |
| HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); |
| |
| |
| String method = request.getMethod(); |
| boolean isGet = "GET".equals(method); |
| if (isGet || "HEAD".equals(method)) { |
| long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); |
| if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { |
| return; |
| } |
| } |
| # 先为当前请求找到1个适配器,找到适配器后返回 |
| protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { |
| if (this.handlerAdapters != null) { |
| for (HandlerAdapter adapter : this.handlerAdapters) { |
| if (adapter.supports(handler)) { |
| return adapter; |
| } |
| } |
| } |
| throw new ServletException("No adapter for handler [" + handler + |
| "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); |
| } |
- 查看DispatcherServlet,执行目标方法
| mv = ha.handle(processedRequest, response, mappedHandler.getHandler()) |
| public interface HandlerAdapter { |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| boolean supports(Object handler); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| @Nullable |
| ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| long getLastModified(HttpServletRequest request, Object handler); |
| |
| } |
- 查看AbstractHandlerMethodAdapter实现
| @Override |
| @Nullable |
| public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) |
| throws Exception { |
| |
| return handleInternal(request, response, (HandlerMethod) handler); |
| } |
| @Nullable |
| protected abstract ModelAndView handleInternal(HttpServletRequest request, |
| HttpServletResponse response, HandlerMethod handlerMethod) throws Exception; |
- 查看实现RequestMappingHandlerAdapter中的handleInternal
| @Override |
| protected ModelAndView handleInternal(HttpServletRequest request, |
| HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { |
| |
| ModelAndView mav; |
| checkRequest(request); |
| |
| |
| if (this.synchronizeOnSession) { |
| HttpSession session = request.getSession(false); |
| if (session != null) { |
| Object mutex = WebUtils.getSessionMutex(session); |
| synchronized (mutex) { |
| mav = invokeHandlerMethod(request, response, handlerMethod); |
| } |
| } |
| else { |
| |
| |
| mav = invokeHandlerMethod(request, response, handlerMethod); |
| } |
| } |
| else { |
| |
| mav = invokeHandlerMethod(request, response, handlerMethod); |
| } |
| |
| if (!response.containsHeader(HEADER_CACHE_CONTROL)) { |
| if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { |
| applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers); |
| } |
| else { |
| prepareResponse(response); |
| } |
| } |
| |
| return mav; |
| } |
| @Nullable |
| protected ModelAndView invokeHandlerMethod(HttpServletRequest request, |
| HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { |
| |
| ServletWebRequest webRequest = new ServletWebRequest(request, response); |
| try { |
| WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); |
| ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); |
| |
| ServletInvocableHandlerMethod 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); |
| |
| ModelAndViewContainer mavContainer = new ModelAndViewContainer(); |
| mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); |
| modelFactory.initModel(webRequest, mavContainer, invocableMethod); |
| mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); |
| |
| AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); |
| asyncWebRequest.setTimeout(this.asyncRequestTimeout); |
| |
| WebAsyncManager 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(); |
| LogFormatUtils.traceDebug(logger, traceOn -> { |
| String formatted = LogFormatUtils.formatValue(result, !traceOn); |
| return "Resume with async result [" + formatted + "]"; |
| }); |
| invocableMethod = invocableMethod.wrapConcurrentResult(result); |
| } |
| |
| invocableMethod.invokeAndHandle(webRequest, mavContainer); |
| if (asyncManager.isConcurrentHandlingStarted()) { |
| return null; |
| } |
| |
| return getModelAndView(mavContainer, modelFactory, webRequest); |
| } |
| finally { |
| webRequest.requestCompleted(); |
| } |
| } |
- 参数解析器-HandlerMethodArgumentResolver
| 确定将要执行的目标方法的每一个参数的值是什么; |
| SpringMVC目标方法能写多少种参数类型。取决于参数解析器。 |

| 当前解析器是否支持解析这种参数 |
| 支持就调用 resolveArgument |

| invocableMethod.invokeAndHandle(webRequest, mavContainer); |
| public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, |
| Object... providedArgs) throws Exception { |
| |
| Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); |
| 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); |
| Assert.state(this.returnValueHandlers != null, "No return value handlers"); |
| try { |
| this.returnValueHandlers.handleReturnValue( |
| returnValue, getReturnValueType(returnValue), mavContainer, webRequest); |
| } |
| catch (Exception ex) { |
| if (logger.isTraceEnabled()) { |
| logger.trace(formatErrorForReturnValue(returnValue), ex); |
| } |
| throw ex; |
| } |
| } |
- ctrl+鼠标点击invokeForRequest
| @Nullable |
| public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { |
| Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs); |
| if (this.logger.isTraceEnabled()) { |
| this.logger.trace("Arguments: " + Arrays.toString(args)); |
| } |
| |
| return this.doInvoke(args); |
| } |
| Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); |
| protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { |
| MethodParameter[] parameters = this.getMethodParameters(); |
| if (ObjectUtils.isEmpty(parameters)) { |
| return EMPTY_ARGS; |
| } else { |
| Object[] args = new Object[parameters.length]; |
| |
| for(int i = 0; i < parameters.length; ++i) { |
| MethodParameter parameter = parameters[i]; |
| parameter.initParameterNameDiscovery(this.parameterNameDiscoverer); |
| args[i] = findProvidedArgument(parameter, providedArgs); |
| if (args[i] == null) { |
| if (!this.resolvers.supportsParameter(parameter)) { |
| throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver")); |
| } |
| |
| try { |
| args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); |
| } catch (Exception var10) { |
| if (this.logger.isDebugEnabled()) { |
| String exMsg = var10.getMessage(); |
| if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) { |
| this.logger.debug(formatArgumentError(parameter, exMsg)); |
| } |
| } |
| |
| throw var10; |
| } |
| } |
| } |
| |
| return args; |
| } |
| } |
| @Override |
| @Nullable |
| public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, |
| NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { |
| |
| HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter); |
| if (resolver == null) { |
| throw new IllegalArgumentException("Unsupported parameter type [" + |
| parameter.getParameterType().getName() + "]. supportsParameter should be called first."); |
| } |
| return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory); |
| } |
- 挨个判断所有参数解析器那个支持解析这个参数,查看getArgumentResolver方法
| @Nullable |
| private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) { |
| HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter); |
| if (result == null) { |
| for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) { |
| if (resolver.supportsParameter(parameter)) { |
| result = resolver; |
| this.argumentResolverCache.put(parameter, result); |
| break; |
| } |
| } |
| } |
| return result; |
| } |
| @Override |
| @Nullable |
| public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, |
| NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { |
| |
| NamedValueInfo namedValueInfo = getNamedValueInfo(parameter); |
| MethodParameter nestedParameter = parameter.nestedIfOptional(); |
| |
| Object resolvedName = resolveStringValue(namedValueInfo.name); |
| if (resolvedName == null) { |
| throw new IllegalArgumentException( |
| "Specified name must not resolve to null: [" + namedValueInfo.name + "]"); |
| } |
| |
| Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest); |
| if (arg == null) { |
| if (namedValueInfo.defaultValue != null) { |
| arg = resolveStringValue(namedValueInfo.defaultValue); |
| } |
| else if (namedValueInfo.required && !nestedParameter.isOptional()) { |
| handleMissingValue(namedValueInfo.name, nestedParameter, webRequest); |
| } |
| arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType()); |
| } |
| else if ("".equals(arg) && namedValueInfo.defaultValue != null) { |
| arg = resolveStringValue(namedValueInfo.defaultValue); |
| } |
| |
| if (binderFactory != null) { |
| WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name); |
| try { |
| arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter); |
| } |
| catch (ConversionNotSupportedException ex) { |
| throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(), |
| namedValueInfo.name, parameter, ex.getCause()); |
| } |
| catch (TypeMismatchException ex) { |
| throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(), |
| namedValueInfo.name, parameter, ex.getCause()); |
| } |
| } |
| |
| handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest); |
| |
| return arg; |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构