DispatcherServlet源码分析
以下是DispatcherServlet的部分源码,不想看源码的可以直接看 总结。
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.
//2-1. 根据当前请求地址找到 那个能处理此请求的类(加了Controller注解的类)
mappedHandler = getHandler(processedRequest);
//如果找不到就404
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
//2-2. 拿到能执行这个类所有方法的适配器(反射工具)。
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.
//2-3. 让适配器去执行目标方法(加了RequestMapping注解的方法),将目标方法执行后的返回值作为视图名 并保存到ModelAndView中。(无论方法的返回值怎么写,适配器最后都会把执行后的结果封装成ModelAndView)
/* ha就是“2-2”得到的适配器 */
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);
}
/* 转发到目标页面 */
//2-4. 根据方法最终执行后封装的ModelAndView 转发到对应页面。(ModelAndView中的数据可以从请求域中获取)
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);
}
}
}
}
-
DispatcherServlet拦截到所有请求。
-
DispatcherServlet调用自己的doDispatch()方法处理这个请求。处理流程:
-
调用自己的getHandler()方法: 根据当前的请求地址找到能处理这个请求的 目标处理器类(就是加了Controller注解的类)。
-
然后,调用自己的getHandlerAdapter()方法: 根据当前的处理器类,获取能执行这个 处理器方法(加了RequestMapping注解的方法)的适配器(HandlerAdapter)。
-
再然后,调用适配器(RequestMappingHandlerAdapter)对象ha的handle()方法: 让获取到的适配器 执行目标方法,并返回一个ModelAndView对象。
-
最后,根据返回ModelAndView对象的信息转发到具体页面。此ModelAndView中的模型数据可以在request中取出。
-
getHandler()是如何找到目标类的
ioc容器启动时会把每个组件对象创建出来,在创建Controller对象时,spring会扫描每个处理器的配置信息(这些信息通常是在配置文件或注解上),然后spring就知道每个处理器都能处理什么请求,并把这些信息存入一个叫handlerMappings的集合中(HandlerMapping是一个接口,与Map没有关系)。
接上,为什么是集合呢?因为spring在扫描Controller的时候,会根据配置信息的来源把这些信息存入到不同的HandlerMapping中(来自配置文件的信息就存入BeanNameUrlHandlerMapping对象中,来自注解的信息就存入DefaultAnnotationHandlerMapping对象中)。
BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping都有一个名为“handlerMap”的属性。handlerMap是一个map,处理请求的方法与请求地址 的映射信息就在这个map中。
总结: getHandler()会遍历handlerMappings集合中的HandlerMapping实现类,然后查看每个实现类中的handleMap 是否有目标请求的映射信息。如果有就返回带有目标类信息的handler对象;如果没有就报404。