在这篇文章中,将要完整的跟踪一下SpringMVC的执行流程
我们会在浏览器里输入
http://localhost:8060/articles/67/comment?comment=sssss2ssssk1k1
最终的效果是
下面就开始走进源码:
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);
}
}
首先来到了FrameworkServlet的service方法,对于PATCH类型的直接调用processRequest方法,其他类型先调用父类的service方法,在这里我们的是get请求
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
//
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
这是HttpServlet的service方法,在这里面根据不同的请求类型进行了分发
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
由于我们的是get请求,所以来到了FrameworkServlet的doGet方法里面,然后调用了processRequest方法
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取开始处理的时间
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
//保存原来的LocaleContext
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
//设置当前的LocaleContext
LocaleContext localeContext = buildLocaleContext(request);
//保存原来的RequestAttributes
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
//设置当前的RequestAttributes
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
//将当前的RequestAttributes和localeContext设置到LoaleContextHolder和RequestContextHolder中
initContextHolders(request, localeContext, requestAttributes);
try {
//调用都Service方法
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);
}
}
可以看到这个方法首先将当前的RequestAttributes和localeContext设置到LoaleContextHolder和RequestContextHolder中,然后调用模板方法doService,这是在子类中执行,最后执行完后会发布ServletRequestHandledEvent消息
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) + "]");
}
// 根据是否是include类型来决定是否要保存当前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("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// 给request设置属性
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()) {
// 如果是include类型的请求,需要恢复快照信息
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
DispathcerServlet的doService方法将webApplicationContext、localeResolver、themeResolver、outputFlashMap和flashMapManager设置到了request属性中,然后将请求传递到了doDispatch方法中
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
首先会检查是否是上传文件的请求,如果是,需要转型
mappedHandler = getHandler(processedRequest);
解析来会根据request找到对应的Handler
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,会和@RequestMapping里面配置的内容进行匹配,然后根据这个条件找到定义的处理器方法
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);
}
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
首先需要获取我们请求的url,然后根据url和request里面的相关属性调用lookupHandlerMethod方法找到对应的HandlerMethod
List<Match> matches = new ArrayList<Match>();
List<T> directPathMatches = this.urlMap.get(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// No choice but to go through all mappings...
addMatchingMappings(this.handlerMethods.keySet(), matches, request);
}
首先会尝试从urlMap里面直接查找匹配的条件,但是由于我们的url中articleId是动态的,所以获取不到,然后调用addMatchingMappings(this.handlerMethods.keySet(), matches, request),传入的参数是当前controller里面所有的匹配条件
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
for (T mapping : mappings) {
T match = getMatchingMapping(mapping, request);
if (match != null) {
matches.add(new Match(match, this.handlerMethods.get(mapping)));
}
}
}
将所有的匹配条件通过getMatchingMapping和我们的request进行比较,符合条件的会被放到matches中
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
return info.getMatchingCondition(request);
}
然后调用匹配信息的getMatchingCondition进行判断
public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
//开始会将所有需要比对的条件进行判断,如果符合的就会返回相应的值
RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
if (methods == null || params == null || headers == null || consumes == null || produces == null) {
return null;
}
//匹配url
PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
if (patterns == null) {
return null;
}
RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
if (custom == null) {
return null;
}
return new RequestMappingInfo(this.name, patterns,
methods, params, headers, consumes, produces, custom.getCondition());
}
这个方法会对request里面的信息进行匹配,如果都匹配成功了那么会返回一个RequestMappingInfo
for (T mapping : mappings) {
T match = getMatchingMapping(mapping, request);
if (match != null) {
matches.add(new Match(match, this.handlerMethods.get(mapping)));
}
}
匹配成功,会将这个匹配信息和对应的handlerMethod绑定到一起放到matches里面
if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
Collections.sort(matches, comparator);
if (logger.isTraceEnabled()) {
logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
}
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;
}
接着会对返回的matches进行排序,最后会选择最优的handlerMethod进行返回
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
如果找到了handlerMethod,那么在getHandlerInternal方法里面会重新创建要给handlerMethod返回
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
//获得一个处理器链
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
//添加所有的AdaptedInterceptors
chain.addInterceptors(getAdaptedInterceptors());
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
//在mappedInterceptors里面找到拦截当前url的拦截器,添加到链上
for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) {
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
return chain;
}
在返回handler时,不仅仅返回的是一个处理器,而是包含了拦截器链的HandlerExecutionChain,在getHandlerExecutionChain方法中,会将找到的处理器,和拦截当前url的拦截器封装后返回
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
然后有了handler,会根据他来找到HandlerAdapter 来执行它
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");
}
这个方法很简单就是看支不支持执行这个handler,支持就直接返回
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
在正式处理前,会执行拦截器的方法,他们是在请求处理前执行的
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
下面就会调用HandlerAdapter的handle方法正式处理请求
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
然后调用模板方法handleInternal,在RequestMappingHandlerAdapter里面被实现
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
// Always prevent caching in case of session attribute management.
checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
}
else {
// Uses configured default cacheSeconds setting.
checkAndPrepare(request, response, true);
}
首先初始化了处理器SessionAttributesHandler,会根据是否有注释@SessionAttributesHandler是必须的进行不同方式的检查,使用的是checkAndPrepare方法
protected final void checkAndPrepare(
HttpServletRequest request, HttpServletResponse response, int cacheSeconds, boolean lastModified)
throws ServletException {
// Check whether we should support the request method.
String method = request.getMethod();
if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {
throw new HttpRequestMethodNotSupportedException(
method, StringUtils.toStringArray(this.supportedMethods));
}
// Check whether a session is required.
if (this.requireSession) {
if (request.getSession(false) == null) {
throw new HttpSessionRequiredException("Pre-existing session required but none found");
}
}
// Do declarative cache control.
// Revalidate if the controller supports last-modified.
applyCacheSeconds(response, cacheSeconds, lastModified);
}
在这里面会给response设置过期时间
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);
接下来根据是否需要同步执行,选择不同的方式执行invokeHandleMethod方法
ServletWebRequest webRequest = new ServletWebRequest(request, response);
首先将request和response封装到了ServletWebRequest
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);
接着创建WebDataBinderFactory、ModelFactory 、ServletInvocableHandlerMethod
private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
Class<?> handlerType = handlerMethod.getBeanType();
Set<Method> methods = this.modelAttributeCache.get(handlerType);
if (methods == null) {
methods = HandlerMethodSelector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
this.modelAttributeCache.put(handlerType, methods);
}
List<InvocableHandlerMethod> attrMethods = new ArrayList<InvocableHandlerMethod>();
// Global methods first
for (Entry<ControllerAdviceBean, Set<Method>> entry : this.modelAttributeAdviceCache.entrySet()) {
if (entry.getKey().isApplicableToBeanType(handlerType)) {
Object bean = entry.getKey().resolveBean();
for (Method method : entry.getValue()) {
attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
}
}
}
for (Method method : methods) {
Object bean = handlerMethod.getBean();
attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
}
return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
}
在创建ModelFactory的时候,先获取到了处理注释了@SessionAttribute的处理器,然后找到了注释了@ModelAttribute的 方法(在这里是replaceSensitiveWords方法),封装成attrMethods,最后将这些信息封装到ModelFactory中返回
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
回到invokeHandleMethod方法中,创建了ModelAndViewContainer,将flashMap中所有的参数放到mav里面,调用initModel方法,设置ignoreDefaultModelOnRedirect属性
public void initModel(NativeWebRequest request, ModelAndViewContainer mavContainer, HandlerMethod handlerMethod)
throws Exception {
Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
mavContainer.mergeAttributes(sessionAttributes);
invokeModelAttributeMethods(request, mavContainer);
for (String name : findSessionAttributeArguments(handlerMethod)) {
if (!mavContainer.containsAttribute(name)) {
Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
if (value == null) {
throw new HttpSessionRequiredException("Expected session attribute '" + name + "'");
}
mavContainer.addAttribute(name, value);
}
}
}
在initModel方法中,首先会将sessionAttributes里面所有的属性合并到mav中,然后会执行所有找到的被@ModelAttribute注释的方法,最后会检查同时存在sessionAttributes和@ModelAttribute注释的方法的参数,是否被添加了,如果没有 那么添加到mav中
private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer mavContainer)
throws Exception {
while (!this.modelMethods.isEmpty()) {
InvocableHandlerMethod attrMethod = getNextModelMethod(mavContainer).getHandlerMethod();
String modelName = attrMethod.getMethodAnnotation(ModelAttribute.class).value();
if (mavContainer.containsAttribute(modelName)) {
continue;
}
Object returnValue = attrMethod.invokeForRequest(request, mavContainer);
if (!attrMethod.isVoid()){
String returnValueName = getNameForReturnValue(returnValue, attrMethod.getReturnType());
if (!mavContainer.containsAttribute(returnValueName)) {
mavContainer.addAttribute(returnValueName, returnValue);
}
}
}
}
invokeModelAttributeMethods会执行所有被@ModelAttribute注释的方法,然后将返回的结果放到mav中
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
StringBuilder sb = new StringBuilder("Invoking [");
sb.append(getBeanType().getSimpleName()).append(".");
sb.append(getMethod().getName()).append("] method with arguments ");
sb.append(Arrays.asList(args));
logger.trace(sb.toString());
}
Object returnValue = doInvoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]");
}
return returnValue;
}
invokeForRequest执行的时候就用到了参数解析器获取request里面的参数,最后执行方法将结果返回,回到invokeHandleMethod方法中
requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
然后会调用requestMappingMethod.invokeAndHandle方法执行我们的doComment方法
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
在invokeAndHandle里面也是调用了invokeForRequest来执行方法只不过这次comment的值由于被@ModelAttribute注释的方法处理了,已经变成了其他的值,处理完后会返回值:redirect:/showArticle
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType);
Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]");
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
调用handleReturnValue方法来处理返回的结果,首先根据结果的类型找到对应的处理器,然后使用处理器调用handleReturnValue方法来对返回结果进行处理
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
if (returnValue == null) {
return;
}
else if (returnValue instanceof String) {
String viewName = (String) returnValue;
mavContainer.setViewName(viewName);
if (isRedirectViewName(viewName)) {
mavContainer.setRedirectModelScenario(true);
}
}
else {
// should not happen
throw new UnsupportedOperationException("Unexpected return type: " +
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
}
}
处理方式很简单,就是将返回值变成viewName,设置到mav中,但是由于我们的是跳转,还会将mav的RedirectModelScenario属性设置为true
return getModelAndView(mavContainer, modelFactory, webRequest);
方法执行完后,会调用getModelAndView方法返回一个ModelAndView
modelFactory.updateModel(webRequest, mavContainer);
首先就会更新model里面存储的值
public void updateModel(NativeWebRequest request, ModelAndViewContainer mavContainer) throws Exception {
ModelMap defaultModel = mavContainer.getDefaultModel();
if (mavContainer.getSessionStatus().isComplete()){
this.sessionAttributesHandler.cleanupAttributes(request);
}
else {
this.sessionAttributesHandler.storeAttributes(request, defaultModel);
}
if (!mavContainer.isRequestHandled() && mavContainer.getModel() == defaultModel) {
updateBindingResult(request, defaultModel);
}
}
如果执行了SessionStatus#setCompelte方法,会清空SessionAttributes,否则会将SessionAttribute里面的参数从model中提取出来放到SessionAttributes里面,然后,如果当前不是跳转的方法会在model中为一些参数设置上bindingResult
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
return mav;
接下来,会新创建一个ModelAndView,由于我们的返回值是跳转,所有还不能马上返回需要进一步处理,首先获取FlashAttributes,和request,将FlashAttributes里面的属性都放到OutputFlashMap中供跳转后的方法使用
HandlerAdapter的工作完成了回到doDispatch方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
执行拦截器的方法,到这没有问题的话接下来就需要processDispatchResult来处理
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
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);
}
}
首先检查有没有初五,如果有需要给exception生成一个ModelAndView
render(mv, request, response);
接下来调用render渲染页面
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.resolveLocale(request);
response.setLocale(locale);
View view;
if (mv.isReference()) {
// We need to resolve the view name.
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 {
// 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.isDebugEnabled()) {
logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
}
try {
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;
}
}
render的主要工作是找到处理当前ModelAndView的View进行渲染
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isTraceEnabled()) {
logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +
" and static attributes " + this.staticAttributes);
}
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
prepareResponse(request, response);
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}
在这里面调用了renderMergedOutputModel方法,renderMergedOutputModel将request属性中保存的outputFlashMap和FlashMapManager取出,使用FlashMapManager将outFlashMap保存到Session中,然后调用sendRedirect方法使用resposne的sendRedirect方法将请求发出,然后返回到processDispatchResult方法中
mappedHandler.triggerAfterCompletion(request, response, null);
调用拦截器的afterCompletion方法,然后将请求返回到DispatcherServlet,在FrameworkServlet的processRequest方法中将原来的LocaleContext和RequestAttributes的值恢复,并发出ServletRequestHandledEvent消息,最后将请求返回给Servlet容器