Spring MVC工作原理及源码解析 ViewResolver实现原理及源码解析
Posted blayn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring MVC工作原理及源码解析 ViewResolver实现原理及源码解析相关的知识,希望对你有一定的参考价值。
0、ViewResolver原理介绍
- View resolveViewName(String viewName, Locale locale);
该接口的实现类有AbstractCachingViewResolver、BeanNameViewResolver、ContentNegotiatingViewResolver、StandaloneMockMvcBuilder和ViewResolverComposite。
1、AbstractCachingViewResolver:实现带缓存的ViewResolver
public View resolveViewName(String viewName, Locale locale) throws Exception { // 是否启用缓存,可通过setCache()方法或setCacheLimit()方法开启缓存,是一个ConcurrentHashMap,默认缓存大小1024 if (!this.isCache()) { return this.createView(viewName, locale); } else { // 得到 view 在缓存中的 key 值 Object cacheKey = this.getCacheKey(viewName, locale); View view = (View)this.viewAccessCache.get(cacheKey); // 如果没有找到 view 则创建,采用双重校验的方式进行安全创建 if (view == null) { synchronized(this.viewCreationCache) { view = (View)this.viewCreationCache.get(cacheKey); if (view == null) { // 具体的创建方式由子类实现 view = this.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 (this.logger.isTraceEnabled()) { this.logger.trace("Cached view [" + cacheKey + "]"); } } } } } return view != UNRESOLVED_VIEW ? view : null; } }
1.1、ResourceBundleViewResolver
使用ResourceBundleViewResolver配置下bean就可以让视图解释器支持解析多种视图,而UrlBasedViewResolver,就只支持解释单一类型的视图。
<bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver"> <!-- 设定属性文件名为views --> <property name="basename" value="views"></property> </bean>
1.2、XmlViewResolver
<bean class="org.springframework.web.servlet.view.XmlViewResolver"> <property name="location"> <value>/WEB-INF/spring-views.xml</value> </property> </bean>
1.3、UrlBasedViewResolver
支持解释单一类型的视图。
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver"> <property name="prefix" value="/WEB-INF/" /> <property name="suffix" value=".jsp" /> <property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView"/> </bean>
2、其他的 ViewResolver
2.1、BeanNameViewResolver
BeanNameViewResolver 是通过视图名称去容器中获取对应的 view 对象,所以在使用前需要将 view 对象注册到容器中。它没有使用缓存,实现方式如下:
@Override public View resolveViewName(String viewName, Locale locale) throws BeansException { ApplicationContext context = getApplicationContext(); // 根据viewName去容器中查找View对象 if (!context.containsBean(viewName)) { if (logger.isDebugEnabled()) { logger.debug("No matching bean found for view name \'" + viewName + "\'"); } // Allow for ViewResolver chaining... return null; } if (!context.isTypeMatch(viewName, View.class)) { if (logger.isDebugEnabled()) { logger.debug("Found matching bean for view name \'" + viewName + "\' - to be ignored since it does not implement View"); } // Since we\'re looking into the general ApplicationContext here, // let\'s accept this as a non-match and allow for chaining as well... return null; } return context.getBean(viewName, View.class); }
2.2、ContentNegotiatingViewResolver
ContentNegotiatingViewResolver本身不解析解析视图,而是用来整合所有的ViewResolver类,每次请求都会遍历所有的ViewResolver,然后找到最合适的处理View,并将其返回。源码如下:
@Override public View resolveViewName(String viewName, Locale locale) throws Exception { RequestAttributes attrs = RequestContextHolder.getRequestAttributes(); Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes"); // 获取Request的MediaType集合 List<MediaType> requestedMediaTypes = getMediaTypes(((ServletRequestAttributes) attrs).getRequest()); if (requestedMediaTypes != null) { // 通过遍历ViewResolver,获取所有符合条件的View List<View> candidateViews = getCandidateViews(viewName, locale, requestedMediaTypes); // 遍历所有的SmartView,SmartView默认是RedirectView返回 // 否则,根据MediaType最合适的第一个View返回 View bestView = getBestView(candidateViews, requestedMediaTypes, attrs); if (bestView != null) { return bestView; } } if (this.useNotAcceptableStatusCode) { if (logger.isDebugEnabled()) { logger.debug("No acceptable view found; returning 406 (Not Acceptable) status code"); } return NOT_ACCEPTABLE_VIEW; } else { logger.debug("No acceptable view found; returning null"); return null; } }
2.3、StandaloneMockMvcBuilder
StandaloneMockMvcBuilder主要用于单元测试,代码如下所示:
/** * A {@link ViewResolver} that always returns same View.(始终返回同一个View,用于单元测试) */ private static class StaticViewResolver implements ViewResolver { private final View view; public StaticViewResolver(View view) { this.view = view; } @Override public View resolveViewName(String viewName, Locale locale) throws Exception { return this.view; } }
2.4、ViewResolverComposite
ViewResolverComposite是包含如上各个ViewResolver的组合类,其resolveViewName方法代码如下:
@Override public View resolveViewName(String viewName, Locale locale) throws Exception { for (ViewResolver viewResolver : this.viewResolvers) { // 生成View对象 View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { return view; } } return null; }
以上是关于Spring MVC工作原理及源码解析 ViewResolver实现原理及源码解析的主要内容,如果未能解决你的问题,请参考以下文章
Spring MVC工作原理及源码解析 HandlerMapping和HandlerAdapter实现原理及源码解析
Spring MVC工作原理及源码解析 MVC原理介绍与IOC容器整合原理