上篇文章我们主要看了DispatcherServlet在提供服务之间做的初始化工作,大部门工作都在WebApplicationContext中完成,然后WebApplicationContext是DispatcherServlet的一个属性。
在初始操作完成以后,DispatcherServlet可以提供健全的服务了,早先我们也提到了,真正的请求分发在doDispatcher这个方法之中,今天一起来看看这个方法到底做了什么操作。
解析
看代码之前,先提前说明自己自己阅读源码过程中的一点简单思考:
- WebAsyncManager在普通的开发中用不到,在异步处理的时候有用到,这一块我们先忽略
- 关键部分:HandlerMappings,HandlerAdapter,HandlerExecutionChain对这几个熟悉之后基本上就懂了它到底在做什么
一起看代码吧
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 || mappedHandler.getHandler() == 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 (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
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);
}
}
}
}
-
processedRequest意思为处理之后的请求,而它是由checkMultipart(request)方法处理的,我们看下这个方法。
- 判断是不是multipart的请求,默认的判断方式是先判断是不是"POST"请求,然后判断"contentType"是否以multipart开头。
- 如果不满足multipart条件,直接返回request,也就是request没有做任何处理
- 如果满足multipart基本条件, 将multipartRequest转换为StandardMultipartHttpServletRequest请求。
// 检查是否为multipart,如果是的话处理一下。 protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException { if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) { try { return this.multipartResolver.resolveMultipart(request); } catch (MultipartException ex) { if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) { logger.debug("Multipart resolution failed for error dispatch", ex); // Keep processing error dispatch with regular request handle below } else { throw ex; } } } } return request; } // 判断是否为multipart的方法 public boolean isMultipart(HttpServletRequest request) { // Same check as in Commons FileUpload... if (!"post".equalsIgnoreCase(request.getMethod())) { return false; } String contentType = request.getContentType(); return StringUtils.startsWithIgnoreCase(contentType, "multipart/"); } //转换为multipart请求 @Override public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException { return new StandardMultipartHttpServletRequest(request, this.resolveLazily); }
-
获取request的Handler方法,handler被封装为HandlerExecutionChain,HandlerExecutionChain为handler方法加上拦截器的集合。我们定义的拦截器就在HandlerExecutionChain这个类中生效。
HandlerExecutionChain为真正的Handler对象与Interceptor的组合类
HandlerExecutionChanin mappedHandler = getHandler(request),内部细节如下
- 内部获取handler方法,在DispatcherServlet中大部分的处理都要将request或者response作为参数对象。
- 内部获取handler的实现,获取request请求的路径,然后从mappingRegistry中拿到路径匹配的HandlerMethod. HandlerMethod封装了我们平时写的@RequestMapping等之类的方法,还有bean。这些可以通过反射获得
- 获取到HandlerMethod之后,稍作处理封装handler和bean
handlerMethod.createWithResolvedBean()
- 上面获取的是HandlerMethod,getHandler中再次封装handler和interceptors
这些都是为真正的处理请求做准备
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
// 这一步的目的是就是,获取所有的interceptor的对象,然后与当前的handler组合在一起
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);
}
this.mappingRegistry.acquireReadLock();
try {
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
- 通过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.
- Handler的预处理,还记得刚才返回的HandlerExecutionChain封装了Handler和一些拦截器,现在就是调用拦截器的时候。
然后其内部就是我们写拦截器的时候常见的preHandler方法。如果拦截器preHndle返回false,那么请求终止。
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
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;
}
-
这个整个DispatcherServlet中最关键的一步,也可以说是最复杂的一步,单独提取出来也够有很多研究的。
ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
HandlerAdpater让Handler处理request与response,RequestMappingHandlerAdpater是最复杂的一个实现,也是大部分请求中都用到的一个Adpater.
- 检查请求,checkRequest,判断请求是否合法
- 判断是否要对invokeHandlerMethod加锁,不管是否加锁这个方法肯定会执行的。
- 执行invokeHandlerMethod,记得HandlerMethod封装了请求路径映射的Method对象
invokeAndHandler内部调用的是invokeForReuquest,根据当前的请求获取Method对应的参数,然后进行invoke.
argumentResolvers主要用来解析Method的参数,细节以后再看
doInvoke将解析的参数与方法进行invoke.
在invokeMethod之后,设置Response的状态码,然后标记请求已经被处理了。
有关getModelAndView的细节,后续再看
这一步已经完成了请求的处理。
-
applyDefaultViewName,然后进行拦截器的请求完成处理mappedHandler.applyPostHandle(processedRequest, response, mv);这一步与前面的拦截器预处理类似。
- 处理请求分发的结果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) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
- 清除现场工作,如果是multipart的请求,清空上传的multipart.
回顾
整个流程看起来虽然不复杂,内部细节很多,更多的了解细节,后面写代码的时候如果出现了错误排除问题才更方便。
简单来说,重要的组件有HandlerMappings,HandlerAdpaters,HandlerExecutionChain,Handler, 最后还有一些视图处理相关技术。
- 首先获取HandlerExecutionChain,其内部封装了Handler与Method,Interceptor
- 然后获取HandlerAdpater,根据是否support来获取,有顺序的,获取的是第一个
- HandlerExecutionChain的拦截器进行preHandler
- HandlerAdpater处理Handler,Request,Response,内部依靠反射激发我们编写的Bean调用
- HandlerExecutionChain的拦截器postHandler
- 处理dispatcher的结果,对视图相关进行处理
- 最后的清除工作
总结
Spring源码博大精深,看源码的过程,吸收一些大师的写法,学到知识的过程是比较爽的。希望能和大家一起讨论。