一,SpringMVC
SpringMVC从Spring家族上来讲,他是基于Spring框架的,或者应该说成是Spring框架的表现层框架。因为这点在下载SpringMVC源码的时候,也是要求依赖于Spring框架的搭建基础上引入的Module。如图所示,在搭建SpringMVC源码时候,是基于之前Spring源码剖析时搭建的框架引入的,SpringMVC的执行流程大致的分为了四步:
1,前端控制器DispatchServlet的加载(监听,filter过滤器....),加载指定的配置文件SpringMVC.xml
2,包扫描,扫描指定的注解
3,IOC容器的初始化
4,映射处理器的加载,简历请求URL与Method之间的联系并等待请求
★二,前端控制处理器DispatcherServlet的继承结果与源码
继承结构: dispatcherServlet <-- FrameworkServlet <-- HttpServletBean <--HttpServlet,根据继承结构可以发现dispatcherServlet底层实则还是一个Servlet。
HttpServlet: doGet & doPost
底层的基类HttpServlet对于Post,Get请求的处理并没有的做业务上的处理,只是请求协议做了判断判断处理,对于Post,Get请求相比会在上层的子类进行重写。
FrameworkServlet
为什么会跳过HttpServletBean类,因为这个类中并没有对Post,Get请求的方法进行重写,所以 这里直接省略了。然后可以看到该类中doGet与doPost都会把请求提交给类中的processRequest方法,顾名知义,这个方法应该是处理请求的方法! 然后来到该方法中,可以看到该方法进行了一些请求的前置处理后,会把request,reponse对象继续像doService方法中传递,而在该类中该方法为一个抽象方法,那么必定会在dispatcherServlet中去实现这个方法。
★DispatcherServlet
dispatcherServlet doService方法前面会对请求的参数,请求头信息做一些处理,处理完成后会继续将请求响应对象向下传递到doDispatch方法中去,以下则为doDispatch处理请求核心代码详细说明。
★三,SpringMVC请求大致流程源码细节剖析
上面的部分其实已经把SpringMVC请求流程大致说明了,其核心的方法还是在于doDispatch方法中,主要对其中重要的几个方法进行细节分析
doHandler
在SpringMVC中Handler也就是我们通常所说的控制层Controller,点进去之后,handlerMapping里面对Spring支持的配置与注解两种注入方式进行遍历去创建HandlerExecutionChain对象,而这个对象中则包含了请求的Url,返回的也就是Handler的执行器对象。
getHandlerAdapter
对于不同的Handler需要构建不同的适配器去执行请求,这里的HandlerAdapters中包含了Spring的三种适配器类型,最终使用返回的适配器类型为 RequestMappingHandlerAdapter
handler
通过前面获取的适配器去handlerMapping,通过反射方式去调用handler中的HandlerMethod并且返回ModelAndView对象,调用方法的过程无非分为两步,参数的解析,方法的获取与调用。进入到该方法中后会去调用invokeHandlerMethod方法。
invokeHandlerMethod方法很长,这里因为篇幅的问题不做一一的解析,代码中提供了详细的注解,后面着重对invokeAndHandle方法进行跟踪。
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
//获取容器全局配置的InitBinder和当前HandlerMethod所对应的controller中配置initBinder,用于参数的绑定
//initBinder: 作用于一些数据类型的转换操作
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
//获取容器全局配置的ModelAttribute注解的方法
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
//将handlerMethod转换成为一个ServletInvocableHandlerMethod对象
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
//获取所有的容器中配置的argumentResolver
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
//获取所有的容器中配置的returnValueHandler
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
//将前面的创建的WebDataBinderFactory设置到ServletInvocableHandlerMethod中
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
//这里的initModel方法主要用于获取前面的@ModelAttribute标注的方法,保证被标注的方法在handler调用之前被调用
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);
}
//对请求的参数处理,调用目标HandlerMethod,并返回值封装一个ModelAndView对象
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
//对封装的ModelAndView是否需要进行重定向的处理等等
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
进入到invokeAndHandle方法中,主要看前面两个方法,一个是获取目标的Handler,对其参数急性解析与方法调用。 首先进入到invoke方法,可以看到执行方式为反射获取方法传入参数执行,这里应证了上面所述反射。
参数的处理方法getMethodArgumentValues,以下为参数的处理流程,这里没什么好说的,要知道一件事,参数的获取来自Request请求对象。
processDispatchResult 视图渲染的流程
这部分没有什么具体要分析的难点代码,主要搞清楚跳转的流程几个,流程看一下的图
入口: processDispatchResult方法
processDispatchResult -》 render方法
render-》resolveViewName方法
resolveViewName-》 AbstractCachingViewResolver类中的resolveViewName方法
resolveViewName.createView -》类中的UrlBasedViewResolver类中的loadView方法。然后到buildView方法中拼接Url,返回view对象
然后回到DispatcherServlet中的render方法,通过返回的view对象去执行其render方法
然后到AbstractView中调用render方法设置相应投与渲染视图结束
到这里为止SpringMVC的请求大致流程,四个重要的方法全部剖析完成。