ブラシは、スプリングMVCソースコードは、それを記録し、書き込みビット厄介であってもよいです。
DispatcherServlet doDispatchコア方法は、基本的なプロセスは、上記の図に完成さdoDispatch、以下ペーストソース
/ ** *ハンドラに実際のディスパッチを処理します。 * <P>ハンドラが順番にサーブレットのHandlerMappingsを適用することによって得られるであろう。 * HandlerAdapterは、サーブレットのインストールHandlerAdaptersを照会することによって得られることになります *ハンドラクラスをサポートする最初のを見つけます。 * <P>すべてのHTTPメソッドは、この方法で処理されます。それはHandlerAdaptersまたはハンドラまでです *自体は許容されている方法を決定します。 * @paramの要求、現在のHTTPリクエスト * @paramの応答電流HTTPレスポンス * @throws 障害処理の任意の種類の場合に例外を * / 保護 ボイド doDispatch(HttpServletRequestのリクエストをHttpServletResponseの応答)がスロー例外{ HttpServletRequestのprocessedRequest = 要求。 HandlerExecutionChain mappedHandler = nullを。 ブール multipartRequestParsed = 偽; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(リクエスト)。 してみてください{ ModelAndView MV = nullを。 例外dispatchException = nullを。 してみてください{ processedRequest = checkMultipart(リクエスト)。 multipartRequestParsed =(!processedRequest = リクエスト)。 // 現在の要求のためのハンドラを決定します。 mappedHandler = getHandler(processedRequest)。 もし(mappedHandler == NULL ){ noHandlerFound(processedRequest、応答)。 リターン; } // 現在の要求に対するハンドラアダプタを決定します。 HandlerAdapter HA = getHandlerAdapter(mappedHandler.getHandler())。 // プロセス最終更新ハンドラによってサポートされている場合、ヘッダ。 文字列メソッド= request.getMethod()。 ブール isGet = "GET" .equals(方法) もし(isGet || "ヘッド" .equals(メソッド)){ 長い LASTMODIFIED = ha.getLastModified(リクエスト、mappedHandler.getHandler())。 もし(新しい ServletWebRequest(リクエスト、レスポンス).checkNotModified(LASTMODIFIED)&& isGet){ リターン。 } } もし(!mappedHandler.applyPreHandle(processedRequest、応答)){ リターン。 } // 実際のハンドラを呼び出します。 MV = ha.handle(processedRequest、応答、mappedHandler.getHandler())。 もし(asyncManager.isConcurrentHandlingStarted()){ リターン。 } applyDefaultViewName(processedRequest、MV)。 mappedHandler.applyPostHandle(processedRequest、応答、MV)。 } キャッチ(例外例){ dispatchException = 元; } キャッチ(ThrowableのERR){ // 4.3のように、我々している処理エラーは、うまくとしてハンドラメソッドからスロー // @ExceptionHandler方法や他のシナリオのためにそれらを利用可能にします。 dispatchException = 新 NestedServletException( "ハンドラのディスパッチに失敗しました" 、ERR)。 } processDispatchResult(processedRequest、応答、mappedHandler、MV、dispatchException)。 } キャッチ(例外例){ triggerAfterCompletion(processedRequest、応答、mappedHandler、EX)。 } キャッチ(ThrowableのERR){ triggerAfterCompletion(processedRequest、応答、mappedHandler、 新しい NestedServletException( "ハンドラの処理に失敗しました" 、ERR)); } 最後に{ 場合(asyncManager.isConcurrentHandlingStarted()){ // 代わりにpostHandleとafterCompletionの 場合(mappedHandler!= nullの){ mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest、応答)。 } } 他に{ // マルチパートリクエストによって使用されるすべてのリソースをクリーンアップします。 もし(multipartRequestParsed){ cleanupMultipart(processedRequest)。 } } } }
その後、いくつかの重要なノードを分析
ハンドラを取得します。1.
HandlerExecutionChain mappedHandler、これはオブジェクトの実際のスケジューリングで、彼の内部は、ハンドラとインターセプタのシリーズが含まれている、以下は公式のコメントです
ハンドラの実行チェーン、およびHandlerInterceptorハンドラで構成するものの簡単な翻訳。このオブジェクトはHandlerMapping.getHandlerメソッドによって返されます。以下は、クラス図であります
そして、オブジェクトHandlerExecutionChain mappedHandlerを取得する方法を見て
ただ、復帰への最初のものと一致するように、コードを見て、その後、このメソッドはHandlerMapping.getHanlderを見て
コメントを翻訳
要求ハンドラと任意のインターセプタを返します。要因としては、任意のリクエストURL、セッション状態または実装クラスの選択に応じて選択することができます。HandlerExecutionChainリターン・ハンドラ・オブジェクトではなく、インタフェースをマーキング、制約なしのように処理プログラムを含みます。たとえば、別のフレームの使用を許可するHandlerAdapter NIハンドラオブジェクトを書くことができます。一致が見つからない場合、nullが返されます。これは間違いではありません。DispatcherServletは、一致を見つけるために、すべての登録HandlerMapping Beanを照会し、ハンドラがエラーがあるかどうかを判断するために設置されなかった場合のみです。
より一般的な実装クラスRequestMappingHandlerMappingを検索するには
結果は、最初RequestMappingHandlerMapping getHanlder @RequestMappingは、最終的に、対応するメソッドへのパラメータを照合することによってであり、そしてその後HandlerExecutionChain生成対応するハンドラプラスブロッカ・オブジェクト戻りに組み込ま前記しました
RequestMappingHandlerMapping継承
でRequestMappingHandlerMappingとgetHanlderこの方法が見つからない、の最後のAbstractHandlerMappingは、このクラスを達成するために見つけ、赤いボックスの一部の焦点であります
(1)getHandlerInternal,这个主要是根据@RequestMapping中的参数匹配查找对应的handler,RequestMappingHandlerMapping的具体实现在父类AbstractHandlerMethodMapping
(2)getHandlerExecutionChain,这个方法是根据@RequestMapping中的参数匹配对应的拦截器然后和handler组装返回一个HandlerExecutionChain
小结一下,最常见的@Controller和@RequestMapping注册在RequestMappingHandlerMapping中,@RequestMapping中的参数进行匹配
其他的HandlerMapping还有很多,比如WebSocketHandlerMapping,WelcomePageHandlerMapping等,此处不展开
2.获取对应的HandlerAdapter
实现方法为getHandlerAdapter
关键代码为HandlerAdapter的supports,这是一个接口,所以找一个实现类,以RequestMappingHandlerAdapter为例,他的实现在父类AbstractHandlerMethodAdapter中,主要判断这个类是否是HandlerMethod类型
其他的实现类还有SimpleControllerHandlerAdapter(处理继承Controller接口的类),SimpleServletHandlerAdapter(处理Servlet类型的类)
3.获取到mappedHandler和handlerAdapter后,可以执行handlerAdapter的handle方法了,以RequestMappingHandlerAdapter为例
在执行真正的handler之前需要先执行mappedHandler中的applyPreHandle方法,这个主要是调用mappedHandler中对应拦截器的preHandle方法。
之后通过handlerAdapter执行mappedHandler中真正的handler
RequestMappingHandlerAdapter的handle方法有点绕,下面一点一点找
AbstractHandlerMethodAdapter.handle
AbstractHandlerMethodAdapter.handleInternal是一个抽象方法,在RequestMappingHandlerAdapter中实现
然后看RequestMappingHandlerAdapter.invokeHandlerMethod(代码有点长,一张图截不下)
/** * Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView} * if view resolution is required. * @since 4.2 * @see #createInvocableHandlerMethod(HandlerMethod) */ @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(); } }
进入ServletInvocableHandlerMethod.invokeAndHandle
进入最关键的代码InvocableHandlerMethod.invokeForRequest(ServletInvocableHandlerMethod是InvocableHandlerMethod的子类)
先翻译一下注释
在给定请求的上下文中解析其参数值后调用该方法。 参数值通常通过HandlerMethodArgumentResolvers解析器解析。然而,providedArgs参数可以提供直接使用的参数值,即不需要参数解析。提供的参数值示例包括WebDataBinder、SessionStatus或抛出的异常实例。提供的参数值在参数解析器之前检查。 委托给getMethodArgumentValues并使用解析后的参数调用doInvoke。
/** * Invoke the method after resolving its argument values in the context of the given request. * <p>Argument values are commonly resolved through * {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}. * The {@code providedArgs} parameter however may supply argument values to be used directly, * i.e. without argument resolution. Examples of provided argument values include a * {@link WebDataBinder}, a {@link SessionStatus}, or a thrown exception instance. * Provided argument values are checked before argument resolvers. * <p>Delegates to {@link #getMethodArgumentValues} and calls {@link #doInvoke} with the * resolved arguments. * @param request the current request * @param mavContainer the ModelAndViewContainer for this request * @param providedArgs "given" arguments matched by type, not resolved * @return the raw value returned by the invoked method * @throws Exception raised if no suitable argument resolver can be found, * or if the method raised an exception * @see #getMethodArgumentValues * @see #doInvoke */ @Nullable public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { logger.trace("Arguments: " + Arrays.toString(args)); } return doInvoke(args); }
InvocableHandlerMethod.getMethodArgumentValues方法,主要作用为获取参数值,参数值通过HandlerMethodArgumentResolver进行解析。
匹配方式可以参考RequestMappingHandlerAdapter.getDefaultArgumentResolvers方法中具体的HandlerMethodArgumentResolver。
这个HandlerMethodArgumentResolver其实也可以自行扩展,可以参考https://www.jianshu.com/p/40606baf49b8
/** * Get the method argument values for the current request, checking the provided * argument values and falling back to the configured argument resolvers. * <p>The resulting array will be passed into {@link #doInvoke}. * @since 5.1.2 */ protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { 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); args[i] = findProvidedArgument(parameter, providedArgs); if (args[i] != null) { continue; } 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 ex) { // Leave stack trace for later, exception may actually be resolved and handled... if (logger.isDebugEnabled()) { String exMsg = ex.getMessage(); if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) { logger.debug(formatArgumentError(parameter, exMsg)); } } throw ex; } } return args; }
获取到参数后,可以执行doInvoke方法了,这个比较简单,就是使用反射执行对应的方法
/** * Invoke the handler method with the given argument values. */ @Nullable protected Object doInvoke(Object... args) throws Exception { ReflectionUtils.makeAccessible(getBridgedMethod()); try { return getBridgedMethod().invoke(getBean(), args); } catch (IllegalArgumentException ex) { assertTargetBean(getBridgedMethod(), getBean(), args); String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument"); throw new IllegalStateException(formatInvokeError(text, args), ex); } catch (InvocationTargetException ex) { // Unwrap for HandlerExceptionResolvers ... Throwable targetException = ex.getTargetException(); if (targetException instanceof RuntimeException) { throw (RuntimeException) targetException; } else if (targetException instanceof Error) { throw (Error) targetException; } else if (targetException instanceof Exception) { throw (Exception) targetException; } else { throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException); } }
小结一下RequestMappingHandlerAdapter的handle方法的核心为使用HandlerMethodArgumentResolver处理参数,之后使用反射方式执行controller中的method。
最后总结一下我们最常见的@RequestMapping和@Controller在Spring MVC中的执行过程
从RequestMappingHandlerMapping获取对应的HandlerExecutionChain mappedHandler
然后使用RequestMappingHandlerAdapter.handle 方法处理mappedHandler生成modelAndView
之后交由ViewResoler生成view,最后response根据view进行渲染