刷了一遍spring mvc源码,记录一下,写的可能有点乱。

DispatcherServlet的核心方法为doDispatch,上图中的流程基本都在doDispatch中完成,下面贴上源码
/**
* Process the actual dispatching to the handler.
* <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
* to find the first that supports the handler class.
* <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
* themselves to decide which methods are acceptable.
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
*/
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);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
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;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
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);
}
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);
}
}
}
}
然后分析一下几个关键的节点
1.获取handler
HandlerExecutionChain mappedHandler,这个为实际调度的对象,他的内部包含一个handler和一系列的拦截器,下面为官方注释

简单翻译一下,处理程序执行链,由handler和HandlerInterceptor组成。由HandlerMapping.getHandler方法返回这个对象。下面为类图

然后看一下如何获取HandlerExecutionChain mappedHandler这个对象


看代码只要匹配到第一个就返回了,然后看一下这个HandlerMapping.getHanlder方法

翻译一下注释
返回此请求的处理程序和任何拦截器。可以根据请求URL、会话状态或实现类选择的任何因素进行选择。 返回的HandlerExecutionChain包含一个处理程序对象,而不是标记接口,因此处理程序不受任何约束。例如,可以编写HandlerAdapter来允许使用另一个框架的ni处理程序对象。如果没有找到匹配,则返回null。这不是一个错误。DispatcherServlet将查询所有已注册的HandlerMapping bean以查找匹配项,并且只有在没有找到处理程序时才判断是否存在错误。
找一个比较常见的实现类RequestMappingHandlerMapping
先说结果RequestMappingHandlerMapping的getHanlder最终实现方式是通过@RequestMapping中的参数去匹配对应的方法,然后组装成Handler并加上对应的拦截器生成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进行渲染
来源:https://www.cnblogs.com/lz-0011/p/12041381.html