【SpringMVC源码】SpringMVC核心DispatcherServlet底层源码分析
注:其他一些spring源码解读,如果有需要,可以参考:
- 【Spring源码】 后置处理器BeanPostProcessor底层原理分析
- 【spring源码】spring声明式事务底层源码分析
- 【spring源码】ApplicationListener事件监听底层原理
- 【spring源码】AOP底层源码分析
- 【spring源码】spring IOC容器底层源码分析
1.核心业务流程
-
直接上图:
-
DispatcherServlet是SpringMVC当之无愧的核心,SpringMVC也是用它来处理客户端的请求并将其结果发送至客户端。
-
为扒源码方便,我们搞个测试Demo:
-
Controller类:
/**
* todo
*
* @author wangjie
* @version V1.0
* @date 2020/1/13
*/
@Controller
public class HelloController {
/**
* /WEB-INF/views/success.jsp
* @return
*/
@RequestMapping("/suc")
public String success(){
return "success";
}
}
- 配置类:
/**
* SpringMVC只扫描Controller;子容器
*useDefaultFilters=false 禁用默认的过滤规则;
* @author wangjie
* @version V1.0
* @date 2020/1/13
*/
@ComponentScan(value="com.code",includeFilters={
@Filter(type=FilterType.ANNOTATION,classes={Controller.class})
},useDefaultFilters=false)
@EnableWebMvc
public class AppConfig extends WebMvcConfigurerAdapter {
/**
* 配置视图
* @param registry
*/
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
//默认所有的页面都从 /WEB-INF/ xxx .jsp
registry.jsp("/WEB-INF/views/", ".jsp");
}
/**
* 静态资源访问
* @param configurer
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
/**
* 拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyFirstInterceptor()).addPathPatterns("/**");
}
}
/**
* Spring的容器不扫描controller;父容器
*
* @author wangjie
* @version V1.0
* @date 2020/1/13
*/
@ComponentScan(value="com.code",excludeFilters={
@Filter(type=FilterType.ANNOTATION,classes={Controller.class})
})
public class RootConfig {
}
/**
* web容器启动的时候创建对象;调用方法来初始化容器以前前端控制器
*
* @author wangjie
* @version V1.0
* @date 2020/1/13
*/
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* 获取根容器的配置类;(Spring的配置文件) 父容器
* @return
*/
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{RootConfig.class};
}
/**
* 获取web容器的配置类(SpringMVC配置文件) 子容器;
* @return
*/
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{AppConfig.class};
}
/**
* 获取DispatcherServlet的映射信息
* /:拦截所有请求(包括静态资源(xx.js,xx.png)),但是不包括*.jsp;
* /*:拦截所有请求;连*.jsp页面都拦截;jsp页面是tomcat的jsp引擎解析的;
* @return
*/
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
- 搂草打兔子,再来个拦截器
/**
* 拦截器
*
* @author wangjie
* @version V1.0
* @date 2020/1/13
*/
public class MyFirstInterceptor implements HandlerInterceptor {
/**
* 目标方法运行之前执行
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("preHandle..."+request.getRequestURI());
return true;
}
/**
* 目标方法执行正确以后执行
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...");
}
/**
* 页面响应以后执行
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("afterCompletion...");
}
}
- 最后搞个success.jsp页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>success!</h1>
</body>
- 运行效果
2.DispatcherServlet底层源码分析
- 用idea打开DispatcherServlet类图:
- 一路往上看DispatcherServlet继承于FrameworkServlet,FrameworkServlet继承于HttpServletBean,HttpServletBean又继承于HttpServlet
- 看到HttpServlet我想大家应该多少明白DispatcherServlet是如何起作用了,说到底,它就是一个servlet
- 是servlet那它就会有我们熟悉的service(),方法,我们从上而下,看是谁重写了service()方法:
- HttpServletBean没有,再向下。
- FrameworkServlet:
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
//重点
processRequest(request, response);
}
else {
//调用父类的方法,再在面
super.service(request, response);
}
}
//父类HttpServlet的service
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//简单来说就是根据请求类型来调用相应的doXXX()方法,例如doPost(req, resp),doGet(req, resp);
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader("If-Modified-Since");
if (ifModifiedSince < lastModified / 1000L * 1000L) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
//而d这些oXXX()方法,例如doPost(req, resp),doGet(req, resp);又在FrameworkServlet里被重写,我们再回FrameworkServlet
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//又是它。。。重点
processRequest(request, response);
}
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//又是它。。。重点
processRequest(request, response);
}
- service()方法在FrameworkServlet被重写,而在这个被重写的service()方法方法里,忽略那些多余的代码,无论如何调用,都会走到processRequest(request, response);方法
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//----------------------------------这些以下不用看---------------------------------
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
initContextHolders(request, localeContext, requestAttributes);
//----------------------------------这些以上不用看---------------------------------
try {
//这里,重点
doService(request, response);
}
catch (ServletException ex) {
failureCause = ex;
throw ex;
}
catch (IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
if (logger.isDebugEnabled()) {
if (failureCause != null) {
this.logger.debug("Could not complete request", failureCause);
}
else {
if (asyncManager.isConcurrentHandlingStarted()) {
logger.debug("Leaving response open for concurrent processing");
}
else {
this.logger.debug("Successfully completed request");
}
}
}
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
- processRequest()方法只有一行值得我们重视,就是doService(request, response);
- 我们看FrameworkServlet里的doService(request, response);方法
protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
throws Exception;
- 它是个抽象方法,它是实现就在我们今天的主角DispatcherServlet里:
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
//日志记录,不用管
if (logger.isDebugEnabled()) {
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
}
// 一堆设置,不用看
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<String, Object>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// 又一堆设置,不看
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
try {
//重点中的核心,核心中的重点
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
- 排除前面一堆代码不用管,我们只看这个方法里的这一行代码:doDispatch(request, response);
- 如果说DispatcherServlet是SpringMVC核心,那doDispatch()就是DispatcherServlet的核心,它的地位就像是springIOC容器初始化时的refresh()方法.
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);
// 根据当前请求地址找到能处理这个请求的目标处理器
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 根据当前处理器获取到能执行这个处理器方法的适配器
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;
}
}
//执行所有拦截器的PreHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 执行目标方法,返回一个ModelAndView 对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
//执行所有拦截器的PostHandle方法
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);
}
}
}
}
- doDispatch()中的重点步骤:
1,getHandler(processedRequest),根据当前请求地址找到能处理这个请求的目标处理器
2,getHandlerAdapter(mappedHandler.getHandler());根据当前处理器获取到能执行这个处理器方法的适配器
3,mappedHandler.applyPreHandle(processedRequest, response)执行所有拦截器的PreHandle方法
4,handle(processedRequest, response, mappedHandler.getHandler());执行目标方法,返回一个ModelAndView 对象
5,mappedHandler.applyPostHandle(processedRequest, response, mv);执行所有拦截器的PostHandle方法
6,processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);返回响应
-
可以对照着核心流程图看:
-
现在我们就上面的主要步骤一个一个看
2.1 getHandler(processedRequest),根据当前请求地址找到能处理这个请求的目标处理器
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//遍历所有的handlerMappings
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
//尝试获取跟请求对应的HandlerExecutionChain
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
//返回HandlerExecutionChain
return handler;
}
}
return null;
}
- 遍历所有的映射器,找到对应的处理执行链返回
- 我们重新Debug运行测试用例,请求测试地址:
- 我们可以看到handlerMappings映射器处理器有5个
- 我们继续运行:
- 找到了对应的handlerMappings,返回HandlerExecutionChain 处理器执行链
- HandlerExecutionChain 中包含了与请求相对应的Controller和拦截器
2.2 getHandlerAdapter(mappedHandler.getHandler());根据当前处理器获取到能执行这个处理器方法的适配器
- 拿到了对应的HandlerExecutionChain,从里面getHandler()拿到处理器,根据处理器开始找对应的适配器:
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 +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
- 接着Debug
- handlerAdapters适配器有3种,挨个遍历
- 找到对应适配器,返回
2.3 mappedHandler.applyPreHandle(processedRequest, response)执行所有拦截器的PreHandle方法
- 我们扒下源码:
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];
//执行拦截器preHandle方法
if (!interceptor.preHandle(request, response, this.handler)) {
//如果执行拦截器preHandle方法返回false
triggerAfterCompletion(request, response, null);
return false;
}
//记录已执行拦截器数量,后面会用到
this.interceptorIndex = i;
}
}
//所有拦截器preHandle方法都返回true时返回true
return true;
}
/
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
//如果有拦截器preHandle方法返回false,就执行拦截器的afterCompletion()方法
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
- 注释已经很详细,我们直接Debug:
- 获取所有拦截器,一共拿到3个,其中只有MyFirstInterceptor是我们自定义的,继续执行:
- 遍历到MyFirstInterceptor,我们继续:
- 以此类推,等所有拦截器preHandle方法都返回true时,方法返回
- 我们可以看一下此时的日志:
[2020-01-17 03:30:41,753] Artifact springmvc-annotation:war: Artifact is deployed successfully
[2020-01-17 03:30:41,754] Artifact springmvc-annotation:war: Deploy took 4,136 milliseconds
preHandle.../suc
- 完美,我们继续。
2.4 handle(processedRequest, response, mappedHandler.getHandler());执行目标方法,返回一个ModelAndView 对象
- 源码:
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
Class<?> clazz = ClassUtils.getUserClass(handler);
//获取session注解
Boolean annotatedWithSessionAttributes = this.sessionAnnotatedClassesCache.get(clazz);
if (annotatedWithSessionAttributes == null) {
annotatedWithSessionAttributes = (AnnotationUtils.findAnnotation(clazz, SessionAttributes.class) != null);
this.sessionAnnotatedClassesCache.put(clazz, annotatedWithSessionAttributes);
}
if (annotatedWithSessionAttributes) {
checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
}
else {
checkAndPrepare(request, response, true);
}
// 判断是否异步
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
return invokeHandlerMethod(request, response, handler);
}
}
}
//执行方法,具体细节看下面
return invokeHandlerMethod(request, response, handler);
}
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//拿到方法的解析器
ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
//用方法解析器根据当前请求地址找到真正的执行目标方法
Method handlerMethod = methodResolver.resolveHandlerMethod(request);
//创建一个方法执行器
ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
//包装原生的request, response
ServletWebRequest webRequest = new ServletWebRequest(request, response);
//创建一个隐含模型
ExtendedModelMap implicitModel = new BindingAwareModelMap();
//真正的执行目标方法
Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
ModelAndView mav =
methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
return mav;
}
- 目标方法的执行主要细节都在invokeHandlerMethod()方法里,具体看代码注释
2.5 mappedHandler.applyPostHandle(processedRequest, response, mv);执行所有拦截器的PostHandle方法
- 源码:
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
//获取所有源码
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
//逆序遍历
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
//执行拦截器的postHandle方法
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
- 跟之前执行拦截器的PreHandle方法一脉相承,唯一需要注意的时,执行顺序是逆序
- 这里拦截器的执行顺序图
2.6 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);返回响应
- 源码:
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
//会判断是否存在异常:如果存在异常,则执行HandlerExceptionResolver进行异常处理
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);
}
}
// 重点,渲染视图
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()) {
return;
}
if (mappedHandler != null) {
//这个方法在调用拦截器的PreHandle方法返回false时调过,用来调用拦截器的afterCompletion方法
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
- 这个方法里首先会判断是否存在异常:如果存在异常,则执行HandlerExceptionResolver进行异常处理
- 然后进行视图渲染
- 最后执行拦截器的afterCompletion方法
- 这里的重点就视图渲染 render()方法
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale);
View view;
if (mv.isReference()) {
// 用系统的视图解析器得到一个view对象.
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// 不需要查找:ModelAndView对象包含实际的View对象
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.isDebugEnabled()) {
logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
}
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 + "] in DispatcherServlet with name '" +
getServletName() + "'", ex);
}
throw ex;
}
}
- 选择一个适合的ViewResolver视图解析器(必须是已经注册到Spring容器中的ViewResolver)拿到一个vew对象
- 最后进行渲染
3.SpringMVC的九大组件
- 上面扒源码的时候,出现很多像处理器,适配器,视图解析器。。等一些组件,我们来看看它们都是什么时候初始化的。
- DispatcherServlet源码
//文件上传处理器
private MultipartResolver multipartResolver;
//区域解析器,更国际化有关
private LocaleResolver localeResolver;
//主题解析器
private ThemeResolver themeResolver;
//映射器处理器
private List<HandlerMapping> handlerMappings;
//适配器
private List<HandlerAdapter> handlerAdapters;
//异常处理器
private List<HandlerExceptionResolver> handlerExceptionResolvers;
//
private RequestToViewNameTranslator viewNameTranslator;
//FlashMap管理器,springMVC重定向携带数据的功能
private FlashMapManager flashMapManager;
//视图解析器
private List<ViewResolver> viewResolvers;
- 这九大组件都是接口,也是规范。
- 其初始化过程:
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
-
onRefresh方法是spring IOC容器留个子类来实现的,会在容器启动的时候调用,具体详见:
-
我们来看其中几个组件初始化方法:
-
initMultipartResolver(context);初始化文件上传处理器
private void initMultipartResolver(ApplicationContext context) {
try {
//尝试从容器中获得
this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
}
}
catch (NoSuchBeanDefinitionException ex) {
// 如果没有就为null;
this.multipartResolver = null;
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +
"': no multipart request handling provided");
}
}
}
- initHandlerMappings(context);映射器处理器
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
//detectAllHandlerMappings默认为true
if (this.detectAllHandlerMappings) {
//首先尝试根据类型在容器中寻找
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
try {
//如果detectAllHandlerMappings被配置成了false,就根据beanname在容器里找
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
// 都不行的话就使用默认
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
}
}
}
- 首先尝试根据类型在容器中寻找
- 如果有配置detectAllHandlerMappings被配置成了false,就根据beanname在容器里找
- 都不行的话就使用默认
- 其实这九大组件的初始化大都这个套路,想进一步了解可以自己翻翻源码。
- 要注意的是如果使用默认的话,会使用org.springframework.web.servlet包下的DispatcherServlet.properties配置文件中配置的
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
4.总结
- 图解:
4.1 描述
-
- 用户向服务器发送请求,请求被SpringMVC 前端控制器 DispatcherServlet捕获;
-
- DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI):
-
- 根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;
-
- DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。
-
- 如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(…)方法【正向】
-
- 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
① HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
② 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
③ 数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
④ 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
- 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
-
- Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
-
- 此时将开始执行拦截器的postHandle(…)方法【逆向】
-
- 根据返回的ModelAndView(此时会判断是否存在异常:如果存在异常,则执行HandlerExceptionResolver进行异常处理)选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet,根据Model和View,来渲染视图
-
- 在返回给客户端时需要执行拦截器的AfterCompletion方法【逆向】
-
- 将渲染结果返回给客户端