SpringMVC过程
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 {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 检查是否为文件上传请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 2、3、4
// Determine handler for the current request.
// 根据当前请求找到哪个类能来处理,返回的对象为HandlerExecutionChain
// HandlerMapping存储了所有请求和处理器之间的关系,HandlerExecutionChain表示某一个请求和处理器之间的关系,列表·循环·非null返回Handler
// mappedHandler即为图中的HandlerExecution
mappedHandler = getHandler(processedRequest);
// 如果没有找到Handler能处理这个请求,
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 5、8
// Determine handler adapter for the current request.
// 根据mappedHandler也就是图中的HandlerExcution也就是HandlerExecutionChain类的对象,找到对应的HandlerAdapter(反射工具AnnotationMethodHandlerAdapter)
//查找方式和上面查找HandlerExcutionChain一样,在列表中用for循环查找
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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//6、7
// Actually invoke the handler.真正的执行处理器的方法
// 处理器的方法被调用,(HandlerAdapter调用Controller,图中6、7步,ha即HandlerAdapter)
// 即Controller方法的语句执行,比如你在Controller类中有一个log.info("aaa")或"aaa".sout,这时候运行完这行代码,命令行里就有了aaa的输出了
// 返回ModelAndView,保存Controller方法返回值作为视图名
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 如Controller没有返回值,则设置默认的视图名
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);
}
// 9、10、11、12
// 转发到目标页面
// processedRequest(包装后的Request(检查是否为文件传输的Request))
// 根据方法最终执行完成后封装的ModelAndView,转发到对应页面,同时ModelAndView中的Model即数据也可以从请求域中获取。该方法见下文
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);
}
}
}
}
// 图1中 3 查找Handler 获得图中的HandlerExecution即HandlerExecutionChainll类的对象
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
HandlerMapping接口有两个实现类,基于配置文件的和基于注解的
// 图1中 5
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable 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.isTraceEnabled()) {
logger.trace("No view rendering, null ModelAndView returned.");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
// Exception (if any) is already handled..
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
/**
* Render the given ModelAndView.
* <p>This is the last stage in handling a request. It may involve resolving the view by name.
* @param mv the ModelAndView to render
* @param request current HTTP servlet request
* @param response current HTTP servlet response
* @throws ServletException if view is missing or cannot be resolved
* @throws Exception if there's a problem rendering the view
*/
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale =
(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
View view;
String viewName = mv.getViewName();
if (viewName != null) {
// We need to resolve the view name.
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
// Delegate to the View object for rendering.
if (logger.isTraceEnabled()) {
logger.trace("Rendering view [" + view + "] ");
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "]", ex);
}
throw ex;
}
}
总结:
所有请求都会被DispatcherServlet接受并拦截
继承了HttpServlet类,还是相当于实现了doGet和doPost方法。命令提交到服务器,DispatcherServlet执行doService方法,doService方法调用doDispatch方法。
-
doDispatch方法首先检查request参数是不是文件上传请求,并对参数HttpServletRequest的对象包装。
-
然后调用getHandler方法,这个方法的返回值是HandlerExecutionChain类的对象,getHandler方法就是在handlerMapping列表中for循环查找HandlerExecutionChain,handlerMapping就是包含了所有HandlerExecutionChain对象的一个列表
-
找到关于这个请求的HandlerExecutionChain对象,在将这个对象的getHander方法返回的handler作为参数调用getHandlerAdapter方法在HandlerAdapters列表中查找handlerAdapter
-
得到的HandlerAdapter对象会调用hadle方法,在这个方法执行时,就是controller方法执行的时候。同时这个方法返回的是ModelAndView对象。
-
然后这个doDispatch方法会把ModelAndView作为参数调用processDispatchResult方法,在这个方法中又会调用render方法,再通过reder方法里的resolveViewName方法返回真正的视图名,在转发到视图,并可以在请求域中取出ModelAndView中的模型数据。
英语学习:
mapping 测绘
execution 执行
adapter 适配器
dispatcher 分发器
resolver 分解器
chain 锁链
interceptors 拦截器
render 提供