流程说明
直接看源码理解起来会比较吃力,先放张图在这,让我们对spring mvc核心处理流程有个初步印象。
前端控制器DispacherServlet
是spring mvc框架的核心类,控制整个请求处理的逻辑,由它调用HanlderMapping
、 HandlerAdapter
、ViewResolver
和View
组件的方法完成请求的处理流程。
开始读源码
1,准备工作
首先spring mvc框架把刚用户请求交给DispacherServlet
类的doService方法对请求进行初步加工
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
//一些准备工作
...
//将spring上下文信息存储至request,方便后面的处理器和视图用到
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
// 存储其他框架信息
...
//分发请求
try {
doDispatch(request, response);
}
// 后续工作
...
}
2,开始分发请求
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
int interceptorIndex = -1;
try {
ModelAndView mv;
boolean errorView = false;
try {
processedRequest = checkMultipart(request);
// 步骤1,获取请求的处理器(handler)
// Determine handler for the current request
mappedHandler = getHandler(processedRequest, false);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 步骤2,获取支持处理器的适配器(handlerAdapter)
// 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()) {
String requestUri = urlPathHelper.getRequestUri(request);
logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// Apply preHandle methods of registered interceptors.
HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
if (interceptors != null) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
return;
}
interceptorIndex = i;
}
}
// 步骤3,调用适配器的handle方法处理请求
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// Do we need view name translation?
if (mv != null && !mv.hasView()) {
mv.setViewName(getDefaultViewName(request));
}
// Apply postHandle methods of registered interceptors.
if (interceptors != null) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
}
}
}
catch (ModelAndViewDefiningException ex) {
logger.debug("ModelAndViewDefiningException encountered", ex);
mv = ex.getModelAndView();
}
catch (Exception ex) {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(processedRequest, response, handler, ex);
errorView = (mv != null);
}
// 步骤4,将mv中的模型数据填充(渲染)到response中
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, processedRequest, 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");
}
}
// Trigger after-completion for successful outcome.
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
}
catch (Exception ex) {
// Trigger after-completion for thrown exception.
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
throw ex;
}
catch (Error err) {
ServletException ex = new NestedServletException("Handler processing failed", err);
// Trigger after-completion for thrown exception.
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
throw ex;
}
finally {
// Clean up any resources used by a multipart request.
if (processedRequest != request) {
cleanupMultipart(processedRequest);
}
}
}
步骤1
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
HandlerMapping
是一个请求路径(URL)与处理器(Handler)的映射表。spring有多种处理请求的处理器,常用的如HttpRequestHandler
, Controller
等,因此也有多个HandlerMapping。getHandler方法中,遍历每种HandlerMapping直到获取到,获取的结果是一个HandlerExecutionChain
对象,他包含了Handler
和各种配置的处理器拦截器(HandlerInterceptor
)
步骤2
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: Does your handler implement a supported interface like Controller?");
}
根据处理器获取处理器适配器(HandlerAdaptor),这里用到了适配器模式,我另外一篇学习笔记中单独写了SpringMVC中的适配器模式,这里就不展开了。也是用遍历的方法,调用处理器适配器的supports方法判断适配器是否支持处理器,直到找到为止
步骤3
调用处理器适配器的handler方法,内部是调用具体处理器的处理方法,返回ModelAndView
对象。此时ModelAndView中,只有Model
即数据对象,没有视图对象View
步骤4
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
Locale locale = this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale();
response.setLocale(locale);
String viewName = mv.getViewName();
View view;
if (viewName != null) {
// 步骤4.1 根据视图名称,获取视图对象View
view = this.resolveViewName(viewName, 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());
}
// 步骤4.2 调用视图对象的render方法,将数据模型model以视图规定的格式填充到response中
view.render(mv.getModelInternal(), request, response);
} catch (Exception var8) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" + this.getServletName() + "'", var8);
}
throw var8;
}
}
步骤4.1
@Nullable
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception {
if (this.viewResolvers != null) {
Iterator var5 = this.viewResolvers.iterator();
while(var5.hasNext()) {
ViewResolver viewResolver = (ViewResolver)var5.next();
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
}
return null;
}
遍历视图解析器集合ViewResolvers获取视图。视图解析器使用到了策略模式,在我的另外一篇学习笔记中有关于SpingMVC中策略模式的说明。
常用的视图解析器是内容协商解析器ContentNegotiatingViewResolver
,它不自己解析视图,而是委托给defaultViews属性中关联的视图去解析。可以自己实现View
接口加到defaultViews中。
步骤4.2
视图对象的render方法,将数据Model按照视图规定的格式填充到response中。到此已经得到可以返回给客户的响应。
总结流程及组件
spring mvc处理请求的流程和用到的组件,总结为如下脑图
参考资料
1, SpringMVC 官方中文文档
2, SpringMVC系列(一)核心:处理请求流程
3, SpringMVC执行流程及工作原理