一、整体流程图
二、整体过程
0、客户端向web服务器(比如Tomcat)发送http请求,web服务器对请求进行l解析,解析后的url地址如果匹配了DispatcherServlet的路径(web.xml中会配置他的映射路径),web容器将请求交由DispatcherServlet处理。
1、 DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;(使用 @Controller注解的普通Java类,此处已经定位到了具体的业务处理方法了,所以我们称其为Handler)。
2、 DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(…)方法)
3、在拦截器方法中(preHandler(…)方法),提取请求中的数据模型,填充Handler入参,所以所有准备工作都已做好,开始执行Handler。。
在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
4、业务处理方法返回一个逻辑视图名(View)和模型数据(Model,二者统称ModelAndView)交给 DispatcherServlet
5、DispatcherServlet调用ViewResolver解析出真实的视图对象,得到这个视图对象后,DispatcherServlet就使用Model对其进行渲染,将最后结果返回给用户。
问题思考:
1、DispatcherServlet截获HTTP请求后,它做了什么?
2、如何将请求映射到控制器的方法中
三、具体过程
当一个请求(request)过来,进入DispatcherServlet中
DispatcherServlet中有很多init方法,用来初始化各个组件,比如
以下只是通过看源码来更好理解下他的流程,很多地方是不明白的,慢慢来。
里面有个方法叫 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 err = null;
Exception dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
mappedHandler = this.getHandler(processedRequest, false);
if(mappedHandler == null || mappedHandler.getHandler() == null) {
this.noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ex = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if(isGet || "HEAD".equals(method)) {
long lastModified = ex.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;
}
}
if(!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
err = ex.handle(processedRequest, response, mappedHandler.getHandler());
} finally {
if(asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
this.applyDefaultViewName(request, err);
mappedHandler.applyPostHandle(processedRequest, response, err);
} catch (Exception var27) {
dispatchException = var27;
}
this.processDispatchResult(processedRequest, response, mappedHandler, err, dispatchException);
} catch (Exception var28) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var28);
} catch (Error var29) {
this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var29);
}
} finally {
if(asyncManager.isConcurrentHandlingStarted()) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
} else {
if(multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
}
HandlerExecutionChain mappedHandler = null;
要得到一个请求的处理器执行链,从handlerMappings中得到。
mappedHandler = this.getHandler(processedRequest, false);
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Iterator i$ = this.handlerMappings.iterator();
HandlerExecutionChain handler;
do {
if(!i$.hasNext()) {
return null;
}
HandlerMapping hm = (HandlerMapping)i$.next();
if(this.logger.isTraceEnabled()) {
this.logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name \'" + this.getServletName() + "\'");
}
handler = hm.getHandler(request);
} while(handler == null);
return handler;
}
//mappedHandler 进行判断
if(mappedHandler == null || mappedHandler.getHandler() == null) {
this.noHandlerFound(processedRequest, response);
return;
}
/*
一、如果发的请求的映射是空的。返回的HandlerExecutionChain mappedHandler对象为空表示没有对应的映射执行noHandlerFound方法
经过这个方法 表示没有页面 并且 会进入404 错误页面。
二、当请求的路径url不存在时(没有对应的requestmapping注解方法),但是applicationcontext.xml中存在以下注解时:
<mvc:default-servlet-handler />
作用:它会像一个检查员,对进入DispatcherServlet的URL进行筛查,如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet处理,寻找本地的静态资源,如css js 等 但是 同样的路径不存在 跳转到404页面,如果不是静态资源的请求,才由DispatcherServlet继续理。
三、如果存在映射,继续执行之后的代码:
得到处理器适配器HandlerAdapter
*/
HandlerAdapter ex = this.getHandlerAdapter(mappedHandler.getHandler());
//得到请求方法 如果是GET或者HEAD则不执行拦截器的PreHandle
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if(isGet || "HEAD".equals(method)) {
long lastModified = ex.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;
}
}
//执行applyPreHandle,底层执行拦截器HandlerInterceptor的PreHandle方法
//提取请求中的数据模型,填充Handler入参
if(!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//applyPreHandle方法
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];
if(!interceptor.preHandle(request, response, this.handler)) {
this.triggerAfterCompletion(request, response, (Exception)null);
return false;
}
}
}
return true;
}
//现在可以执行Handler了 返回ModelAndView
//ModelAndView err=null;
err = ex.handle(processedRequest, response, mappedHandler.getHandler());
//随后代码继续执行 调用了 拦截器的 PostHandler方法 ,然后调用 ProcessDispatchResult方法
mappedHandler.applyPostHandle(processedRequest, response, err);
....
....
this.processDispatchResult(processedRequest, response, mappedHandler, err, dispatchException);
//processDispatchResult方法
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);
}
}
}
//其中调用异常解析器
mv = this.processHandlerException(request, response, handler, exception);
//渲染视图的render() 方法 然后页面进行了转发 然后整个流程就已经走完了!!!
//this.render(mv, request, response);
if(!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
if(mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
}
}