先来看一张整体的处理过程图:
下面的Spring源码版本为4.3.12,是目前最新的稳定版本。
源码版本不一致,可能会有稍许差异。
请求的分发 DispatcherServlet.doDispatcher()
先看一下DispatcherServlet方法的核心方法doDispatch:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 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()); 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 ; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return ; } mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return ; } applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { 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()) { if (mappedHandler != null ) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
请求处理器的执行链 HandlerExecutionChain
HandlerExecutionChain主要负责拦截器链的调用,另外还保存了handler的引用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 public class HandlerExecutionChain { private final Object handler; private HandlerInterceptor[] interceptors; private List<HandlerInterceptor> interceptorList; private int interceptorIndex = -1 ; 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]; if (!interceptor.preHandle(request, response, this .handler)) { triggerAfterCompletion(request, response, null ); return false ; } this .interceptorIndex = i; } } return true ; } 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]; interceptor.postHandle(request, response, this .handler, mv); } } } 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 { interceptor.afterCompletion(request, response, this .handler, ex); } catch (Throwable ex2) { logger.error("HandlerInterceptor.afterCompletion threw exception" , ex2); } } } } ... }
从上面的源码可以大致得到拦截器链与handler执行的先后顺序:
检查并解析文件上传请求 DispatcherServlet.checkMultipart()
这个部分在图上没有体现,因为文件上传的请求在项目中占的比重肯定不会很多:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 protected HttpServletRequest checkMultipart (HttpServletRequest request) throws MultipartException { if (this .multipartResolver != null && this .multipartResolver.isMultipart(request)) { if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null ) { logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " + "this typically results from an additional MultipartFilter in web.xml" ); } else if (hasMultipartException(request) ) { logger.debug("Multipart resolution failed for current request before - " + "skipping re-resolution for undisturbed error rendering" ); } else { try { return this .multipartResolver.resolveMultipart(request); } catch (MultipartException ex) { if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null ) { logger.debug("Multipart resolution failed for error dispatch" , ex); } else { throw ex; } } } } return request; }
获取请求处理器 DispacherServlet.getHandler()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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 ; }
RequestMappingHandlerMapping RequestMappingHandlerMapping是匹配@Controller和@RequestMapping注解的,这种方式也是最常用的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping implements MatchableHandlerMapping , EmbeddedValueResolverAware { ... @Override protected boolean isHandler (Class<?> beanType) { return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); } 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); } HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); if (CorsUtils.isCorsRequest(request)) { CorsConfiguration globalConfig = this .globalCorsConfigSource.getCorsConfiguration(request); CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig); executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain; } protected HandlerMethod getHandlerInternal (HttpServletRequest request) throws Exception { String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); if (logger.isDebugEnabled()) { logger.debug("Looking up handler method for path " + lookupPath); } this .mappingRegistry.acquireReadLock(); try { 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 ); } finally { this .mappingRegistry.releaseReadLock(); } } }
获取处理器适配器 DispatcherServlet.getHandlerAdapter()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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" ); }
以上的HandlerAdapter分别用来适配以下几种控制器:
SimpleServletHandlerAdapter适配javax.servlet.Servlet
接口 SimpleControllerHandlerAdapter适配org.springframework.web.servlet.mvc.Controller
接口(这是Spring2.5之前的控制器需要实现的接口) HttpRequestHandlerAdapter适配org.springframework.web.HttpRequestHandler
接口,包括ResourceHttpRequestHandler处理ResourceResolver解析出的静态资源,以及通过Http协议暴露的HTTP invoker。 AnnotationMethodHandlerAdapter是Spring 3.2之前处理@Controller注解类中的@RequestMapping注解方法的适配器。 RequestMappingHandlerAdapter是Spring3.2之后处理@Controller注解类中的@RequestMapping注解方法的适配器。 RequestMappingHandlerAdapter与AnnotationMethodHandlerAdapter相比提供了更多的扩展功能,比如Servlet3支持的异步请求,Controller切面支持注解@ControllerAdvice和ControllerAdviceBean等。
RequestMappingHandlerAdapter 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware , InitializingBean { ... public final ModelAndView handle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handleInternal(request, response, (HandlerMethod) handler); } @Override protected ModelAndView handleInternal (HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav; checkRequest(request); if (this .synchronizeOnSession) { HttpSession session = request.getSession(false ); if (session != null ) { Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { mav = invokeHandlerMethod(request, response, handlerMethod); } } else { mav = invokeHandlerMethod(request, response, handlerMethod); } } else { mav = invokeHandlerMethod(request, response, handlerMethod); } if (!response.containsHeader(HEADER_CACHE_CONTROL)) { if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { applyCacheSeconds(response, this .cacheSecondsForSessionAttributeHandlers); } else { prepareResponse(response); } } return mav; } protected ModelAndView invokeHandlerMethod (HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest (request, response); try { WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); invocableMethod.setHandlerMethodArgumentResolvers(this .argumentResolvers); invocableMethod.setHandlerMethodReturnValueHandlers(this .returnValueHandlers); invocableMethod.setDataBinderFactory(binderFactory); invocableMethod.setParameterNameDiscoverer(this .parameterNameDiscoverer); ModelAndViewContainer mavContainer = new ModelAndViewContainer (); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); modelFactory.initModel(webRequest, mavContainer, invocableMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this .ignoreDefaultModelOnRedirect); AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); asyncWebRequest.setTimeout(this .asyncRequestTimeout); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.setTaskExecutor(this .taskExecutor); asyncManager.setAsyncWebRequest(asyncWebRequest); asyncManager.registerCallableInterceptors(this .callableInterceptors); asyncManager.registerDeferredResultInterceptors(this .deferredResultInterceptors); if (asyncManager.hasConcurrentResult()) { Object result = asyncManager.getConcurrentResult(); mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0 ]; asyncManager.clearConcurrentResult(); if (logger.isDebugEnabled()) { logger.debug("Found concurrent result value [" + result + "]" ); } invocableMethod = invocableMethod.wrapConcurrentResult(result); } invocableMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null ; } return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); } } ... }
请求处理方法 HandlerMethod
HandlerMethod 就代表了我们处理请求的方法,也就是我们写在Controller里面有@RequestMapping注解的方法。
有bean
和method
两个属性就能调用这个方法了。
从上面的RequestMappingHandlerAdapter的代码可以看到我们用的是它的子类ServletInvocableHandlerMethod
,它的继承关系也很简单:
子类InvocableHandlerMethod中有几个重要字段:
WebDataBinderFactory负责创建DataBinder用于将请求参数绑定方法的参数中 HandlerMethodArgumentResolverComposite是一组HandlerMethodArgumentResolver
,用于解析handler方法的参数,比如参数有@PathVariable注解就把请求uri中携带的参数注入进去,如果有@CookieValue注解就把请求Cookie注入,如果有@RequestParam注解就把请求?
后的参数注入进去… ParameterNameDiscoverer负责把handler方法的参数名取出来,方便在没有@RequestParam等任何注解的时候和请求参数的名字匹配。
ServletInvocableHandlerMethod也有一个重要的参数:
HandlerMethodReturnValueHandlerComposite是一组HandlerMethodReturnValueHandler,他们用来处理handler方法的返回值。比如方法上有@ResponseBody注解就把返回值序列化成JSON或XML响应给客户端。 请求处理方法的参数解析和返回值处理 HandlerMethodArgumentResolver 和**HandlerMethodReturnValueHandler**
HandlerMethodArgumentResolver用于解析请求并注入到方法的参数重,可以通过官方文档 查看SpringMVC支持什么类型的参数。
HandlerMethodReturnValueHandler用于处理Controller方法的返回值,可以通过官方文档 查看SpringMVC支持什么类型的返回值。
RequestMappingHandlerAdapter 中有定义了默认的参数解析器和返回值处理器
处理请求分发结果 DispatcherServlet.processDispatchResult()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 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) { 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 ) { mappedHandler.triggerAfterCompletion(request, response, null ); } }
解析视图名并渲染视图 DispatcherServlet.render(), resolveViewName()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 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); if (view == null ) { throw new ServletException ("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + 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 '" + 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; } } protected View resolveViewName (String viewName, Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception { for (ViewResolver viewResolver : this .viewResolvers) { View view = viewResolver.resolveViewName(viewName, locale); if (view != null ) { return view; } } return null ; }
#视图和视图解析器
ViewResolver 和**View**
ViewResolver就是把我们在Controller中返回的viewName解析成一个实际的视图层对象;Spring支持的视图层技术 包括JSP,FreeMarker,Velocity,Groovy,Tiles,PDF,Excel等,还有就是Spring官方比较推荐的Thymeleaf(Spring没有对Thymeleaf直接支持,需要导入Thymeleaf的jar包)。
这些视图解析器解析viewName得到如下的视图对象:
InternalResourceViewResolver InternalResourceViewResolver是用的最多ViewResolver。
想要分析InternalResourceViewResolver,我们还需要看看它父类的代码(resolveViewName方法在父类中):
AbstractCachingViewResolver
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 public abstract class AbstractCachingViewResolver extends WebApplicationObjectSupport implements ViewResolver { public static final int DEFAULT_CACHE_LIMIT = 1024 ; private static final View UNRESOLVED_VIEW = new View () { public String getContentType () { return null ; } public void render (Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) { } }; private volatile int cacheLimit = DEFAULT_CACHE_LIMIT; private boolean cacheUnresolved = true ; private final Map<Object, View> viewAccessCache = new ConcurrentHashMap <Object, View>(DEFAULT_CACHE_LIMIT); private final Map<Object, View> viewCreationCache = new LinkedHashMap <Object, View>(DEFAULT_CACHE_LIMIT, 0.75f , true ) { protected boolean removeEldestEntry (Map.Entry<Object, View> eldest) { if (size() > getCacheLimit()) { viewAccessCache.remove(eldest.getKey()); return true ; } else { return false ; } } }; public View resolveViewName (String viewName, Locale locale) throws Exception { if (!isCache()) { return createView(viewName, locale); } else { Object cacheKey = getCacheKey(viewName, locale); View view = this .viewAccessCache.get(cacheKey); if (view == null ) { synchronized (this .viewCreationCache) { view = this .viewCreationCache.get(cacheKey); if (view == null ) { view = createView(viewName, locale); if (view == null && this .cacheUnresolved) { view = UNRESOLVED_VIEW; } if (view != null ) { this .viewAccessCache.put(cacheKey, view); this .viewCreationCache.put(cacheKey, view); if (logger.isTraceEnabled()) { logger.trace("Cached view [" + cacheKey + "]" ); } } } } } return (view != UNRESOLVED_VIEW ? view : null ); } } protected View createView (String viewName, Locale locale) throws Exception { return loadView(viewName, locale); } protected abstract View loadView (String viewName, Locale locale) throws Exception; }
UrlBasedViewResolver
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 public class UrlBasedViewResolver extends AbstractCachingViewResolver implements Ordered { public static final String REDIRECT_URL_PREFIX = "redirect:" ; public static final String FORWARD_URL_PREFIX = "forward:" ; private String prefix = "" ; private String suffix = "" ; private String[] viewNames; private int order = Integer.MAX_VALUE; protected View createView (String viewName, Locale locale) throws Exception { if (!canHandle(viewName, locale)) { return null ; } if (viewName.startsWith(REDIRECT_URL_PREFIX)) { String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length()); RedirectView view = new RedirectView (redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible()); view.setHosts(getRedirectHosts()); return applyLifecycleMethods(viewName, view); } if (viewName.startsWith(FORWARD_URL_PREFIX)) { String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length()); return new InternalResourceView (forwardUrl); } return super .createView(viewName, locale); } protected View loadView (String viewName, Locale locale) throws Exception { AbstractUrlBasedView view = buildView(viewName); View result = applyLifecycleMethods(viewName, view); return (view.checkResource(locale) ? result : null ); } protected AbstractUrlBasedView buildView (String viewName) throws Exception { AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass()); view.setUrl(getPrefix() + viewName + getSuffix()); String contentType = getContentType(); if (contentType != null ) { view.setContentType(contentType); } view.setRequestContextAttribute(getRequestContextAttribute()); view.setAttributesMap(getAttributesMap()); Boolean exposePathVariables = getExposePathVariables(); if (exposePathVariables != null ) { view.setExposePathVariables(exposePathVariables); } Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes(); if (exposeContextBeansAsAttributes != null ) { view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes); } String[] exposedContextBeanNames = getExposedContextBeanNames(); if (exposedContextBeanNames != null ) { view.setExposedContextBeanNames(exposedContextBeanNames); } return view; } }
InternalResourceViewResolver
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public class InternalResourceViewResolver extends UrlBasedViewResolver { private static final boolean jstlPresent = ClassUtils.isPresent( "javax.servlet.jsp.jstl.core.Config" , InternalResourceViewResolver.class.getClassLoader()); private Boolean alwaysInclude; public InternalResourceViewResolver () { Class<?> viewClass = requiredViewClass(); if (InternalResourceView.class == viewClass && jstlPresent) { viewClass = JstlView.class; } setViewClass(viewClass); } public InternalResourceViewResolver (String prefix, String suffix) { this (); setPrefix(prefix); setSuffix(suffix); } @Override protected Class<?> requiredViewClass() { return InternalResourceView.class; } public void setAlwaysInclude (boolean alwaysInclude) { this .alwaysInclude = alwaysInclude; } @Override protected AbstractUrlBasedView buildView (String viewName) throws Exception { InternalResourceView view = (InternalResourceView) super .buildView(viewName); if (this .alwaysInclude != null ) { view.setAlwaysInclude(this .alwaysInclude); } view.setPreventDispatchLoop(true ); return view; } }
InternalResourceView,RedirectView,JstlView 前面ViewResolver中涉及到了三个View的实现类:InternalResourceView,RedirectView,JstlView
AbstractView
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public abstract class AbstractView extends WebApplicationObjectSupport implements View , BeanNameAware { ... 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); } protected abstract void renderMergedOutputModel ( Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception;}
InternalResourceView
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public class InternalResourceView extends AbstractUrlBasedView { ... protected void renderMergedOutputModel ( Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { exposeModelAsRequestAttributes(model, request); exposeHelpers(request); String dispatcherPath = prepareForRendering(request, response); RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath); if (rd == null ) { throw new ServletException ("Could not get RequestDispatcher for [" + getUrl() + "]: Check that the corresponding file exists within your web application archive!" ); } if (useInclude(request, response)) { rd.include(request, response); } else { rd.forward(request, response); } } }
RedirectView
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class RedirectView extends AbstractUrlBasedView implements SmartView { ... protected void renderMergedOutputModel (Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws IOException { ... sendRedirect(request, response, targetUrl, this .http10Compatible); } protected void sendRedirect (HttpServletRequest request, HttpServletResponse response, String targetUrl, boolean http10Compatible) throws IOException { String encodedURL = (isRemoteHost(targetUrl) ? targetUrl : response.encodeRedirectURL(targetUrl)); if (http10Compatible) { HttpStatus attributeStatusCode = (HttpStatus) request.getAttribute(View.RESPONSE_STATUS_ATTRIBUTE); if (this .statusCode != null ) { response.setStatus(this .statusCode.value()); response.setHeader("Location" , encodedURL); } else if (attributeStatusCode != null ) { response.setStatus(attributeStatusCode.value()); response.setHeader("Location" , encodedURL); } else { response.sendRedirect(encodedURL); } } else { HttpStatus statusCode = getHttp11StatusCode(request, response, targetUrl); response.setStatus(statusCode.value()); response.setHeader("Location" , encodedURL); } } }
本作品采用 知识共享署名 4.0 国际许可协议 进行许可。
转载时请注明原文链接 :https://blog.hufeifei.cn/2017/12/J2EE/SpringMVC/