目录
DispatherServlet类分析
首先,我们看DispatherServlet类中的初始化试图解析器的方法
我们逐步来看代码:
this.viewResolvers = null;
//首先上方的代码表示可以加载多个视图解析器
//detectAllViewResolvers表示加载容器中所有的视图器
if (this.detectAllViewResolvers) {
// Find all ViewResolvers in the ApplicationContext, including ancestor contexts.
在容器的上下文中寻找所有的视图解析器
Map<String, ViewResolver> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.viewResolvers = new ArrayList<>(matchingBeans.values());
// We keep ViewResolvers in sorted order.
AnnotationAwareOrderComparator.sort(this.viewResolvers);
}
}
但是通常detectAllViewResolvers的默认值会设置成为TRUE,默认会加载所有视图解析器
Map<String, ViewResolver> matchingBeans这个Map集合,通常寻找的所有的视图解析器之后全部存储到Map集合中,名字和本身的对象存储,之后调用AnnotationAwareOrderComparator.sort(this.viewResolvers)方法,对所有的视图解析器进行排序,按照本身的order属性
之后发送请求之后,中央控制器收到请求之后,会调用service方法,紧接着调用processRequest方法,之后进入到DispatherServlet类中的doService方法中,之后调用如下图:
resolveViewName方法:
我们细看resolveViewName方法:
public View resolveViewName(String viewName, Locale locale) throws Exception {
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
List<MediaType> requestedMediaTypes = getMediaTypes(((ServletRequestAttributes) attrs).getRequest());
if (requestedMediaTypes != null) {
//筛选出所有的候选视图
List<View> candidateViews = getCandidateViews(viewName, locale, requestedMediaTypes);
//选出最好的视图
View bestView = getBestView(candidateViews, requestedMediaTypes, attrs);
if (bestView != null) {
return bestView;
}
}
getCandidateViews方法
进入getCandidateViews方法:
//遍历所有的视图解析器
for (ViewResolver viewResolver : this.viewResolvers) {
//从每一个视图解析其中寻找视图
View view = viewResolver.resolveViewName(viewName, locale);
//如果视图不为NULL,就加入集合
if (view != null) {
candidateViews.add(view);
}
AbstractUrlBasedView 类
AbstractUrlBasedView 类中:
protected View loadView(String viewName, Locale locale) throws Exception {
AbstractUrlBasedView view = buildView(viewName);
//先构建VIEW 最后再检查
View result = applyLifecycleMethods(viewName, view);
//检查视图是否存在,不存在返回NULL
return (view.checkResource(locale) ? result : null);
}
//默认返回true,证明可能返回的view是损坏的用不了的,有风险的
public boolean checkResource(Locale locale) throws Exception {
return true;
}
FreeMarkerView类
FreeMarkerView类中:
public boolean checkResource(Locale locale) throws Exception {
String url = getUrl();
Assert.state(url != null, "'url' not set");
try {
// Check that we can get the template, even if we might subsequently get it again.
getTemplate(url, locale);
return true;
}
catch (FileNotFoundException ex) {
// Allow for ViewResolver chaining...
return false;
}
catch (ParseException ex) {
throw new ApplicationContextException("Failed to parse [" + url + "]", ex);
}
catch (IOException ex) {
throw new ApplicationContextException("Failed to load [" + url + "]", ex);
}
}
checkResource方法有非常好的检查view,Thymeleaf中并没有检查的方法
getBestView方法
进入getBestView方法:
当每一个视图解析器的mediaType与候选视图的ContentType相同时就返回,当有多个视图都相同时返回第一个,按视图解析器的order优先级来排序