SpringMVC 请求调用过程
image.png
SpringVMC和Spring关系
springMVC源码分析--容器初始化(二)DispatcherServlet
http://blog.csdn.net/qq924862077/article/details/52809312
springMVC作为spring项目中的子项目,其可以和spring web容器很好的兼容。其实现机制就是springMVC也会自己初始化一个IOC容器,然后将spring web的IOC容器作为父容器,这样就可以使用父容器中注入的bean了,由于是向上继承的,所以父容器无法使用子容器注入的Bean。
调用过程分析(3、4过程有点糙)
-
调用过程
image.png
1.spring mvc请所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责负责对请求进行真正的处理工作。
2.DispatcherServlet查询一个或多个HandlerMapping,找到处理请求的Controller.
默认使用(DefaultAnnotationHandlerMapping),注解方式,@Cointroller。
3.DispatcherServlet请求提交到目标Controller
4.Controller进行业务逻辑处理后,会返回一个ModelAndView
5.Dispathcher查询一个或多个ViewResolver视图解析器,找到ModelAndView对象指定的视图对象
6.视图对象负责渲染返回给客户端
-
这个图是正确的
image.png
架构类图
image.png请求调用过程
对于请求到Controller的映射,比较重要的是HandlerMapping和HandlerAdapter,HandlerMapping是封装了处理对象,HandlerAdapter是用来处理请求参数。
- 入口
DispatcherServlet.doDispatch()。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
//1、文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析;
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
//2.通过HandlerMapping,将请求映射到处理器(返回一个HandlerExecutionChain,它包括一个处理器、多个HandlerInterceptor拦截器);
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
this.noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = this.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 (this.logger.isDebugEnabled()) {
this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
// 3调用HandlerExecutionChain的interceptor,处理多个拦截器
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 4调用controller
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 5调用HandlerExecutionChain的interceptor
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
// 6.解析视图、处理异常
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
- 上面第2步
其实有两步:获取 HandlerMapping, 获取HandlerExecutionChain。
1)获取 HandlerMapping,lookupHandlerMethod 会通过请求路径从集合中找到要处理的方法。
这个方法的类 AbstractHandlerMethodMapping 在初始化的时候会调 afterPropertiesSet 将系统中所有的@RequestMapping注解解析,放在一个Map里面。这样上就可以从map中查找了。这步很重要!
handlerMapping 封装了要处理的类,方法 等信息
image.png2)获取HandlerExecutionChain, 会持有HandlerMapping 和 拦截器数组。
image.png image.png
- 上面第6步
这个Adapter的作用主要是把请求中的参数和Controller方法中的参数对应起来,所以就会做一些类型转换相应的工作
image.png会调 RequestMappingHandlerAdapter.handleInternal() 方法
image.png
- 真正调用在这里
RequestMappingHandlerAdapter.invokeHandlerMethod, 这里做了很多事。
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
ModelAndView var15;
try {
//1获取类型转换器
WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
//2创建Method映射
ServletInvocableHandlerMethod invocableMethod = this.createInvocableHandlerMethod(handlerMethod);
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
//3创建ModelandView包装器
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
//4异步相关
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);
Object result;
if (asyncManager.hasConcurrentResult()) {
result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Found concurrent result value [" + result + "]");
}
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
//5.1 调用 controller 地方
invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
if (asyncManager.isConcurrentHandlingStarted()) {
result = null;
return (ModelAndView)result;
}
var15 = this.getModelAndView(mavContainer, modelFactory, webRequest);
} finally {
webRequest.requestCompleted();
}
return var15;
}
------------------------------------
// 调用 controller 地方
5.1会调这里
-----------------------------------
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 5.1.1获取参数并调用controller,返回controller 结果
Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
this.setResponseStatus(webRequest);
if (returnValue == null) {
if (this.isRequestNotModified(webRequest) || this.getResponseStatus() != null || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
} else if (StringUtils.hasText(this.getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
try {
this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception var6) {
if (this.logger.isTraceEnabled()) {
this.logger.trace(this.getReturnValueHandlingErrorMessage("Error handling return value", returnValue), var6);
}
throw var6;
}
}
-----------------------------------
5.1.1
----------------------------------
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 获取参数,这里会从request中取出对应的参数填充到方法参数中,返回值就是方法参数
// 主要过程遍历方法参数,对每个参数从request中找值塞入
Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(this.getMethod(), this.getBeanType()) + "' with arguments " + Arrays.toString(args));
}
// 调用controller 对应方法
Object returnValue = this.doInvoke(args);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Method [" + ClassUtils.getQualifiedMethodName(this.getMethod(), this.getBeanType()) + "] returned [" + returnValue + "]");
}
return returnValue;
}
现在requestMappingMethod中有了方法信息,有了请求信息,接下来就获取请求参数并调用controller 对应方法。
- 最后使用反射调用controller
-
最后将结果组装成 ModelAndView
image.png
-
调用过程时序图
image.png -
doDispatch调用过程(SpringMVC核心)
最后将view渲染到response里了
image.png
- 渲染使用View的render()方法,真正执行的是具体的视图渲染。比如FreeMarkerView的doRender()方法。
渲染就是将model中的值放到request中,使用request.setAttribute()。