SpringMVC 的大概流程整理
Contents
入口:
从 Tomcat 到 SpringMVC 的 DispatcherServlet
org.apache.catalina.core.StandardWrapperValve
:
第一步: 获取 wrapper
容器
StandardWrapper wrapper = (StandardWrapper) getContainer();
第二步: 根据容器 wrapper
获取相应的 servlet
if (!unavailable) {
servlet = wrapper.allocate();
}
第三步: 获取 filter 调用链
ApplicationFilterFactory
可以获取当前 Web 应用的所有 Filter 配置信息. 并以此来匹配相应的请求的 filter
ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet)
第四步: 调用 filter
filterChain.doFilter(request.getRequest(), response.getResponse());
第五步: 根据调用链来执行当前的 filter
private void internalDoFilter(ServletRequest request, ServletResponse response){
...
filter.doFilter(request, response, this);
...
}
可以看到, 当前有2个 filter ,然后它会按顺序, 从上到下依次执行相应的 filter
第六步: filter 执行完后, 就开始执行相应的 servlet 了.
servlet.service(request, response);
org.springframework.web.servlet.FrameworkServlet
-> super.service(request, response);
因为一般来说, 只有 org.springframework.web.servlet.DispatcherServlet
继承了 FrameworkServlet
, SpringMVC 就是通过 DispatcherServlet
来进行分发请求的(通过它的名字 DispatcherServlet 也可以大概知道它的字面意思, 调度器 servlet).
从 DispatcherServlet 到 Controller
第一步: 判断是不是 checkMultipart (即上传文件类型的 Request)
使用 org.springframework.web.multipart.commons.CommonsMultipartResolver
来判断.
如果 checkMultipart
返回的 HttpServletRequest
对象跟 doDispatch
方法中的 HttpServletRequest
对象引用不相等, 则表明是 MultipartHttpServletRequest
而不是普通的 HttpServletRequest
.
第二步: 根据Request对象查找相应的 Handler
即根据请求的路径如
/hello
来查找相应的 Controller 及其方法对象, 以便要调用.
protected HandlerExecutionChain getHandler(HttpServletRequest request);
该方法是从 private List<HandlerMapping> handlerMappings;
对象中匹配.
查找 HandlerMethod
HandlerMapping.getHandler(request)
->
org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(HttpServletRequest request)
->
Object handler = getHandlerInternal(request);
protected HandlerMethod getHandlerInternal(HttpServletRequest request);
HandlerMethod 就是根据 url 匹配成功后返回的相应的方法对象.
->
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
成功后就返回该 handlerMehtod 对象了.
第三步: 根据 MethodHanlder 获取 HandlerExecutionChain , 即 handler 的调用链
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
可以看到, 是根据相应的请求 URL 来获取相应的 Interceptor
拦截器, 并设置到调用链对象中.
例子这里只有2个 interceptor
注意, Inteceptor 还分区很多类型的. 例如有:
可以看到上面的源码, 如果是 MappedInterceptor
类型的, 它还要匹配该请求的 URL 是否满足该 Interceptor 的条件, 只有满足条件的, 才会将它加到该 Handler 的调用链中.
完成后, 可以看到调用链的对象已经设置好了
第四步: 获取 HandlerAdapter
默认情况下, 有三种
private List<HandlerAdapter> handlerAdapters;
第五步: 应用 interceptors
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
如果有返回 false 的, 表示中断了. 返回 true 表示继续向下执行.
第六步: 实际开始调用 Handler
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod)
org.springframework.web.servlet.mvc.method.annotation.invokeHandlerMethod(...)
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);
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
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();
if (logger.isDebugEnabled()) {
logger.debug("Found concurrent result value [" + result + "]");
}
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
- 首先根据 hanlderMethod 获取
WebDataBinderFactory
- 再获取
ModelFactory
- 根据
HandlerMethod
构建ServletInvocableHandlerMethod
- 然后为它们设置相应的处理器及属性
最后开始调用
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()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
try {
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}
可以看到该方法的第一行 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
这就是真正调用 HandlerMethod 来处理请求了.
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"' with arguments " + Arrays.toString(args));
}
Object returnValue = doInvoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"] returned [" + returnValue + "]");
}
return returnValue;
}
invokeForRequest
的第一行 getMethodArgumentValues
, 这里就是构建的们的 Controller 对应的方法的参数了. 所有参数的自动处理, 就是在这里进行的.处理完后, 就会根据这些参数来正式调用该 Controller 的方法了.
getMethodArgumentValues
处理:
根据所注册的 argumentResolvers
来判断当前位置的参数, 是否被相应的 argumentResolvers
所支持解析. 如果匹配的话, 则会调用它来进行参数解析.
最终会调用 ServletRequestMethodArgumentResolver.resolveArgument()
方法来解析参数.
所有的参数如果都正确的解析完后, 就会真正调用我们自己的 Controller 的相应的方法了.