为什么研究doDispatch方法? 来看下图,Springmvc 的很多组件都是围绕着DispatchServlet工作的。而其doDispatch方法用代码的方式呈现了如下图的完整的流程
前端控制器DispatcherServlet(不需要工程师开发),由框架提供
作用:接收请求,响应结果,相当于转发器,中央处理器。有了dispatcherServlet减少了其它组件之间的耦合度。
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。
spring-webmvc-4.3.14
先来看看
protected void initStrategies(ApplicationContext context) {
this.initMultipartResolver(context);
this.initLocaleResolver(context);
this.initThemeResolver(context);
this.initHandlerMappings(context);
this.initHandlerAdapters(context);
this.initHandlerExceptionResolvers(context);
this.initRequestToViewNameTranslator(context);
this.initViewResolvers(context);
this.initFlashMapManager(context);
}
由上可知:容器在启动时就初始化了很多组件(也即,这些组件由容器提供并初始化),以供后续直接使用。
我们以initHandlerMappings为例
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
//从容器中查找所有的handlerMapping类,放到一个Map集合中,命名为matchingBeans
Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerMappings);//还给排个序
}
} else {
try {
HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
} catch (NoSuchBeanDefinitionException var3) {
}
}
if (this.handlerMappings == null) {
this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
if (this.logger.isDebugEnabled()) {
this.logger.debug("No HandlerMappings found in servlet '" + this.getServletName() + "': using default");
}
}
}
DispatcherServlet.java 的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,processedRequest意思为处理之后的请求,而它是由checkMultipart(request)方法处理的
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
//2,获取request的Handler方法,handler被封装为HandlerExecutionChain,
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
this.noHandlerFound(processedRequest, response);
return;
}
//3,通过Handler获取HandlerAdpater,主要是用来做很多预处理
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;
}
}
//4,Handler的预处理,还记得刚才返回的HandlerExecutionChain封装了Handler和一些拦截器,现在就是调用拦截器的时候。
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//5,HandlerAdpater让Handler处理request与response,获取ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//6,
this.applyDefaultViewName(processedRequest, mv);
//7,这一步与前面的拦截器预处理类似。
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
//8,处理请求分发的结果
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);
}
}
}
以上八条注释,就是每次接受请求以后,DispatchServlet的活动全过程。
- processedRequest意思为处理之后的请求,而它是由checkMultipart(request)方法处理的。
- 判断是不是multipart的请求,默认的判断方式是先判断是不是"POST"请求,然后判断"contentType"是否以multipart开头。
- 如果不满足multipart条件,直接返回request,也就是request没有做任何处理
- 如果满足multipart基本条件, 将multipartRequest转换为StandardMultipartHttpServletRequest请求。
以下是部分源码
protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
//如果是Multipart请求,将multipartRequest转换为StandardMultipartHttpServletRequest请求。
try {
return this.multipartResolver.resolveMultipart(request);
} catch (MultipartException var3) {
if (request.getAttribute("javax.servlet.error.exception") == null) {
throw var3;
}
}
//返回request
return request;
}
public boolean isMultipart(HttpServletRequest request) {
//先判断是不是post请求,如果不是直接返回false
if (!"post".equalsIgnoreCase(request.getMethod())) {
return false;
} else {
//再判断"contentType"是否以multipart开头。
String contentType = request.getContentType();
return StringUtils.startsWithIgnoreCase(contentType, "multipart/");
}
}
2, 获取request的Handler方法,handler被封装为HandlerExecutionChain,HandlerExecutionChain为handler方法加上拦截器的集合。我们定义的拦截器就在HandlerExecutionChain这个类中生效。
HandlerExecutionChain processedRequest = this.checkMultipart(request);
HandlerExecutionChain为真正的Handler对象与Interceptor的组合类
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//handlerMapping组件是在启动时就初始化过的,可以在此直接使用。
//springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
Iterator var2 = this.handlerMappings.iterator();
HandlerExecutionChain handler;
do {
if (!var2.hasNext()) {
return null;
}
HandlerMapping hm = (HandlerMapping)var2.next();
if (this.logger.isTraceEnabled()) {
this.logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + this.getServletName() + "'");
}
//由handlerMapping的getHandler方法,以request为参数,获取HandlerExecutionChain
//HandlerMapping 实例根据自己实现类的方式去尝试查找 Handler
handler = hm.getHandler(request);
} while(handler == null);
return handler;
}
处理器映射器HandlerMapping(不需要工程师开发),由框架提供
作用:根据请求的url查找Handler
HandlerMapping负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
而 HandlerMapping 具体有哪些实现类呢。下图可以一览
先来看一下 AbstractHandlerMapping,它实现了 HandlerMapping 接口中的 getHandler() 方法,源码如下所示
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//继续查找Handler
Object handler = this.getHandlerInternal(request);
if (handler == null) {
handler = this.getDefaultHandler();
}
if (handler == null) {
return null;
} else {
//如果是个字符串如“index.html”,就去找对应的静态资源
if (handler instanceof String) {
String handlerName = (String)handler;
handler = this.getApplicationContext().getBean(handlerName);
}
HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
CorsConfiguration config = globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig;
executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
}
可以看到在这个方法中又调用了 getHandlerInternal() 方法获取到了 Handler 对象,而 Handler 对象具体内容是由它的子类去定义的。
再看
有很多方式,
HandlerExecutionChanin mappedHandler = getHandler(request),内部细节如下
- 内部获取handler方法,在DispatcherServlet中大部分的处理都要将request或者response作为参数对象。
- 内部获取handler的实现,获取request请求的路径,然后从mappingRegistry中拿到路径匹配的HandlerMethod. HandlerMethod封装了我们平时写的@RequestMapping等之类的方法,还有bean。这些可以通过反射获得
- 获取到HandlerMethod之后,稍作处理封装handler和bean
handlerMethod.createWithResolvedBean()
- 上面获取的是HandlerMethod,getHandler中再次封装handler和interceptors
这些都是为真正的处理请求做准备
3, 根据 Handler 来找到支持它的 HandlerAdapter,通过 HandlerAdapter 执行这个 Handler 得到 ModelAndView 对象
通过Handler获取HandlerAdpater,HandlerAdpater作为适配器,真正做东西的还是Handler,HandelAdpater做了很多的预处理,不过它的接口很简单。
public interface HandlerAdapter {
// 判断当前的HandlerAdpater是否支持handler的实例,也就是当前的adapter能否使用传过来的Handler
boolean supports(Object handler);
// 使用传过来的handler来处理请求
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
//和Servlet的getLastModified功能基本一致
long getLastModified(HttpServletRequest request, Object handler);
}
在DispatcherServlet中getHandlerAdapter的实现,则是遍历HandlerAdpaters,然后返回第一个支持handler的Adpater.
4,
- Handler的预处理,还记得刚才返回的HandlerExecutionChain封装了Handler和一些拦截器,现在就是调用拦截器的时候。
然后其内部就是我们写拦截器的时候常见的preHandler方法。如果拦截器preHndle返回false,那么请求终止
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
HandlerInterceptor interceptor = interceptors[i];
//如果有哪个拦截器的preHandler
if (!interceptor.preHandle(request, response, this.handler)) {
//触发拦截器的afterCompletion方法并返回false
this.triggerAfterCompletion(request, response, (Exception)null);
return false;
}
}
}
return true;
}
如上图,逐个执行拦截器的preHandler,如果有哪个拦截器的preHandler返回false,则直接触发其afterCompletion方法并停止执行后面所有拦截器
5, HandlerAdpater让Handler处理request与response,RequestMappingHandlerAdpater是最复杂的一个实现,也是大部分请求中都用到的一个Adpater.
- 检查请求,checkRequest,判断请求是否合法
- 判断是否要对invokeHandlerMethod加锁,不管是否加锁这个方法肯定会执行的。
- 执行invokeHandlerMethod,记得HandlerMethod封装了请求路径映射的Method对象
最终执行的是public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean下的如下方法:handleInternal()
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
this.checkRequest(request);
ModelAndView mav;
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized(mutex) {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader("Cache-Control")) {
if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
} else {
this.prepareResponse(response);
}
}
return mav;
}
- 检查请求,checkRequest,判断请求是否合法
- 判断是否要对invokeHandlerMethod加锁,不管是否加锁这个方法肯定会执行的。
- 执行invokeHandlerMethod,(如下)记得HandlerMethod封装了请求路径映射的Method对象
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
ModelAndView var15;
try {
WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = this.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);
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);
}
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;
}
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//获取方法的参数
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));
}
//用这些参数,doInvoke
Object returnValue = this.doInvoke(args);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Method [" + ClassUtils.getQualifiedMethodName(this.getMethod(), this.getBeanType()) + "] returned [" + returnValue + "]");
}
return returnValue;
}
以上就是获取getModelAndView的一些细节
8,处理请求分发的结果processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);看其中的代码也没有多复杂,相对容易理解
- 检查处理请求的时候是否有异常抛出,前面如果有异常抛出会被捕获,然后传递到这一步,然后根据异常处理错误页面
- 如果ModelAndView有值,不管是正常显示还是错误页面,进行渲染
- 做最后的清除工作,并且执行拦截器的完全执行完成操作
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
this.logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException)exception).getModelAndView();
} else {
Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
mv = this.processHandlerException(request, response, handler, exception);
errorView = mv != null;
}
}
if (mv != null && !mv.wasCleared()) {
this.render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
} else if (this.logger.isDebugEnabled()) {
this.logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + this.getServletName() + "': assuming HandlerAdapter completed request handling");
}
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
}
}
}
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale);
View view;
if (mv.isReference()) {
view = this.resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + this.getServletName() + "'");
}
} else {
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a View object in servlet with name '" + this.getServletName() + "'");
}
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + this.getServletName() + "'");
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
view.render(mv.getModelInternal(), request, response);
} catch (Exception var7) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" + this.getServletName() + "'", var7);
}
throw var7;
}
}