官方文档中的流程
首先看下SpringMVC文档上给的流程图:
这张图片给了我们大概的执行流程:
-
用户请求首先发送到前端控制器DispatcherServlet,DispatcherServlet根据请求的信息来决定使用哪个页面控制器Controller(也就是我们通常编写的Controller)来处理该请求。找到控制器之后,DispatcherServlet将请求委托给控制器去处理。
-
接下来页面控制器开始处理用户请求,页面控制器会根据请求信息进行处理,调用业务层等等,处理完成之后,会把结果封装成一个ModelAndView返回给DispatcherServlet。
-
前端控制器DispatcherServlet接到页面控制器的返回结果后,根据返回的视图名选择相应的试图模板,并根据返回的数据进行渲染。
-
最后前端控制器DispatcherServlet将结果返回给用户。
更具体的流程
上面只是总体流程,接下来我们稍微深入一点,看下更具体的流程,这里没有图,只有步骤解析:
-
用户请求发送到前端控制器DispatcherServlet。
-
前端控制器DispatcherServlet接收到请求后,DispatcherServlet会使用HandlerMapping来处理,HandlerMapping会查找到具体进行处理请求的Handler对象。
-
HandlerMapping找到对应的Handler之后,并不是返回一个Handler原始对象,而是一个Handler执行链,在这个执行链中包括了拦截器和处理请求的Handler。HandlerMapping返回一个执行链给DispatcherServlet。
-
DispatcherServlet接收到执行链之后,会调用Handler适配器去执行Handler。
-
Handler适配器执行完成Handler(也就是我们写的Controller)之后会得到一个ModelAndView,并返回给DispatcherServlet。
-
DispatcherServlet接收到Handler适配器返回的ModelAndView之后,会根据其中的视图名调用视图解析器。
-
视图解析器根据逻辑视图名解析成一个真正的View视图,并返回给DispatcherServlet。
-
DispatcherServlet接收到视图之后,会根据上面的ModelAndView中的model来进行视图渲染完成之后,DispatcherServlet就可以将结果返回给用户了。
-
源码
DispatcherServlet是一个Servlet,我们知道在Servlet在处理一个请求的时候会交给service方法进行处理,这里也不例外,DispatcherServlet继承了FrameworkServlet,首先进入FrameworkServlet的service方法:
-
protected void service(HttpServletRequest request, HttpServletResponse response)
-
throws ServletException, IOException {
-
-
String method = request.getMethod();
-
-
if (method.equalsIgnoreCase(RequestMethod.PATCH.name())) {
-
processRequest(request, response);
-
}
-
else {
-
super.service(request, response);
-
}
-
}
HttpServlet中会根据请求类型的不同分别调用doGet或者doPost等方法,FrameworkServlet中已经重写了这些方法,在这些方法中会调用processRequest进行处理,在processRequest中会调用doService方法,这个doService方法就是在DispatcherServlet中实现的。下面就看下DispatcherServlet中的doService方法的实现。
请求到达DispatcherServlet
doService方法:
-
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
-
-
-
Map<String, Object> attributesSnapshot = null;
-
if (WebUtils.isIncludeRequest(request)) {
-
logger.debug("Taking snapshot of request attributes before include");
-
attributesSnapshot = new HashMap<String, Object>();
-
Enumeration<?> attrNames = request.getAttributeNames();
-
while (attrNames.hasMoreElements()) {
-
String attrName = (String) attrNames.nextElement();
-
if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
-
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()) {
-
return;
-
}
-
-
if (attributesSnapshot != null) {
-
restoreAttributesAfterInclude(request, attributesSnapshot);
-
}
-
}
-
}
DispatcherServlet开始真正的处理,
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;
-
-
-
mappedHandler = getHandler(processedRequest, false);
-
if (mappedHandler == null || mappedHandler.getHandler() == null) {
-
noHandlerFound(processedRequest, response);
-
return;
-
}
-
-
-
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
-
-
-
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;
-
}
-
-
try {
-
-
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
-
}
-
finally {
-
if (asyncManager.isConcurrentHandlingStarted()) {
-
return;
-
}
-
}
-
-
applyDefaultViewName(request, mv);
-
-
mappedHandler.applyPostHandle(processedRequest, response, mv);
-
}
-
catch (Exception ex) {
-
dispatchException = ex;
-
}
-
-
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
-
}
-
catch (Exception ex) {
-
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
-
}
-
catch (Error err) {
-
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
-
}
-
finally {
-
if (asyncManager.isConcurrentHandlingStarted()) {
-
-
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
-
return;
-
}
-
-
if (multipartRequestParsed) {
-
cleanupMultipart(processedRequest);
-
}
-
}
-
}
可以看到大概的步骤还是按照我们上面分析的走的。
查找请求对应的Handler对象
对应着这句代码mappedHandler = getHandler(processedRequest, false);,看下具体的getHandler方法:
-
protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception {
-
return getHandler(request);
-
}
继续往下看getHandler:
-
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
-
-
-
for (HandlerMapping hm : this.handlerMappings) {
-
HandlerExecutionChain handler = hm.getHandler(request);
-
if (handler != null) {
-
return handler;
-
}
-
}
-
return null;
-
}
继续往下看getHandler,在AbstractHandlerMapping类中:
-
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
-
-
Object handler = getHandlerInternal(request);
-
if (handler == null) {
-
-
handler = getDefaultHandler();
-
}
-
if (handler == null) {
-
return null;
-
}
-
-
-
if (handler instanceof String) {
-
String handlerName = (String) handler;
-
handler = getApplicationContext().getBean(handlerName);
-
}
-
-
return getHandlerExecutionChain(handler, request);
-
}
根据requrst获取handler
首先看下根据requrst获取handler步骤getHandlerInternal方法,在AbstractHandlerMethodMapping中:
-
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
-
-
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
-
-
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
-
-
return (handlerMethod != null) ? handlerMethod.createWithResolvedBean() : null;
-
}
看下根据路径寻找handler的方法lookupHandlerMethod:
-
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
-
List<Match> matches = new ArrayList<Match>();
-
-
List<T> directPathMatches = this.urlMap.get(lookupPath);
-
-
if (directPathMatches != null) {
-
addMatchingMappings(directPathMatches, matches, request);
-
}
-
-
if (matches.isEmpty()) {
-
-
addMatchingMappings(this.handlerMethods.keySet(), matches, request);
-
}
-
-
if (!matches.isEmpty()) {
-
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
-
Collections.sort(matches, comparator);
-
-
Match bestMatch = matches.get(0);
-
-
if (matches.size() > 1) {
-
Match secondBestMatch = matches.get(1);
-
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
-
Method m1 = bestMatch.handlerMethod.getMethod();
-
Method m2 = secondBestMatch.handlerMethod.getMethod();
-
throw new IllegalStateException(
-
"Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" +
-
m1 + ", " + m2 + "}");
-
}
-
}
-
-
handleMatch(bestMatch.mapping, lookupPath, request);
-
-
return bestMatch.handlerMethod;
-
}
-
else {
-
return handleNoMatch(handlerMethods.keySet(), lookupPath, request);
-
}
-
}
获取默认Handler
如果上面没有获取到Handler,就会获取默认的Handler。如果还获取不到就返回null。
处理String类型的Handler
如果上面处理完的Handler是String类型的,就会根据这个handlerName获取bean。
封装Handler执行链
上面获取完Handler,就开始封装执行链了,就是将我们配置的拦截器加入到执行链中去,getHandlerExecutionChain:
-
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
-
-
HandlerExecutionChain chain =
-
(handler instanceof HandlerExecutionChain) ?
-
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler);
-
-
chain.addInterceptors(getAdaptedInterceptors());
-
-
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
-
-
for (MappedInterceptor mappedInterceptor : mappedInterceptors) {
-
if (mappedInterceptor.matches(lookupPath, pathMatcher)) {
-
chain.addInterceptor(mappedInterceptor.getInterceptor());
-
}
-
}
-
-
return chain;
-
}
获取对应请求的Handler适配器
getHandlerAdapter:
-
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
-
-
-
for (HandlerAdapter ha : this.handlerAdapters) {
-
if (ha.supports(handler)) {
-
return ha;
-
}
-
}
-
}
缓存的处理
也就是对last-modified的处理
执行拦截器的preHandle方法
就是遍历所有的我们定义的interceptor,执行preHandle方法
使用Handler适配器执行当前的Handler
ha.handle执行当前Handler,我们这里使用的是RequestMappingHandlerAdapter,首先会进入AbstractHandlerMethodAdapter的handle方法:
-
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
-
throws Exception {
-
return handleInternal(request, response, (HandlerMethod) handler);
-
}
handleInternal方法,在RequestMappingHandlerAdapter中:
-
protected final ModelAndView handleInternal(HttpServletRequest request,
-
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
-
-
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
-
-
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 invokeHandleMethod(request, response, handlerMethod);
-
}
-
}
-
}
-
-
return invokeHandleMethod(request, response, handlerMethod);
-
}
组装默认视图名称
前缀和后缀名都加上
执行拦截器的postHandle方法
遍历intercepter的postHandle方法。
处理最后的结果,渲染之类的
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) {
-
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 (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
-
-
return;
-
}
-
-
if (mappedHandler != null) {
-
mappedHandler.triggerAfterCompletion(request, response, null);
-
}
-
}
重点看下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 = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
-
}
-
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 '" + getServletName() + "'");
-
}
-
}
-
-
-
view.render(mv.getModelInternal(), request, response);
-
}
-
-
view.render就是进行视图的渲染,然后跳转页面等处理。