調(diào)用過程
org.springframework.web.servler.ViewResolver
用來決定應(yīng)該用哪個(gè)org.springframework.web.servlet.View
的實(shí)例來創(chuàng)建并發(fā)送給客戶端的response。
Dispatcherservlet 收到一個(gè)由request handler (通常為Controller中處理用戶請求的方法)處理完用戶請求而返回的值之后,在DispatcherServlet#doDispatch
中調(diào)用了processDispatchResult
:
/**
* Handle the result of handler selection and handler invocation, which is
* either a ModelAndView or an Exception to be resolved to a ModelAndView.
*/
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception
之后的call hierarchy如下:
在DispatcherServlet#resolveViewName
中锌历,遍歷當(dāng)前的所有ViewResolver
,調(diào)用其resolveViewName
方法:
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#resolveViewName
的語義就是:對(duì)于給定的viewName
(由Controller返回),若是能夠處理卦碾,則返回對(duì)應(yīng)的View的實(shí)例铺坞,否則返回null,由下一個(gè)ViewResolver 處理蔗坯。
找到合適的view之后康震,即調(diào)用其render方法燎含,將從request handler 返回的數(shù)據(jù)(在spring mvc中稱為model
)宾濒,進(jìn)行數(shù)據(jù)綁定并對(duì)客戶端進(jìn)行相應(yīng):
//DispatcherServlet#render(...):
view.render(mv.getModelInternal(), request, response);
詳情可參考:SpringMVC#mvc-viewresolver
注冊ViewResolver
從上面的代碼可以看到,所有的ViewResolver
保存在DispatcherServlet#viewResolvers
中屏箍,而viewResolvers這個(gè)列表的值從context里面绘梦、與獲取其他bean一樣、來獲雀翱:
private void initViewResolvers(ApplicationContext context) {
this.viewResolvers = null;
if (this.detectAllViewResolvers) {
// Find all ViewResolvers in the ApplicationContext, including ancestor contexts.
Map<String, ViewResolver> matchingBeans =
//從context中獲取類型為ViewResolver的bean
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.viewResolvers = new ArrayList<ViewResolver>(matchingBeans.values());
// We keep ViewResolvers in sorted order.
OrderComparator.sort(this.viewResolvers);
}
}
else {
try {
//從context中獲取類型為ViewResolver的bean
ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
this.viewResolvers = Collections.singletonList(vr);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default ViewResolver later.
}
}
// Ensure we have at least one ViewResolver, by registering
// a default ViewResolver if no other resolvers are found.
if (this.viewResolvers == null) {
this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("No ViewResolvers found in servlet '" + getServletName() + "': using default");
}
}
}
這里可以看到卸奉,ViewResolver是有順序的(可以通過@order 來控制bean的順序),若是多個(gè)ViewResolver可以處理同樣的viewName
颖御,那么排在后面的ViewResolver將不起作用榄棵。
View#render
View#render 方法負(fù)責(zé)輸出最終的HTTP response.
其接收三個(gè)參數(shù):
- Map<String, ?> model: 從Controller那邊獲得的跟業(yè)務(wù)相關(guān)的數(shù)據(jù)
- HttpServletRequest request: ?當(dāng)前的HTTP request
- HttpServletResponse response:當(dāng)前正在構(gòu)建的HTTP response,可將內(nèi)容寫入并發(fā)送給客戶端
SpringMVC 提供了許多默認(rèn)的View的實(shí)現(xiàn)類,可以滿足大部分開發(fā)的需求——?如果完全使用spring框架的話疹鳄。如果你打算自己控制render過程拧略,有自己的一套模板機(jī)制,那么就可以創(chuàng)建自定義View的實(shí)現(xiàn)類了瘪弓。
總結(jié)
這里簡單講述了當(dāng)一個(gè)request被處理完成之后垫蛆,將處理結(jié)果轉(zhuǎn)化為response的過程中涉及到的類。大致流程如下:
- 接收到客戶端的request腺怯,根據(jù)request查找對(duì)應(yīng)的request handler(一般為Controller中的方法)
- request handler處理完之后返回袱饭,spring將處理結(jié)果包裝為
ModelAndView
(將在其他文章中介紹這個(gè)過程) -
DispatcherServlet
根據(jù)ModelAndView
的view name來選擇對(duì)應(yīng)的View:遍歷ViewResolver,ViewResolver根據(jù)view name來返回對(duì)應(yīng)的View的實(shí)現(xiàn)類(或返回null并交給下一個(gè)ViewResolver) - 調(diào)用
View#render
來生成最終的response呛占,在View的實(shí)現(xiàn)類中實(shí)現(xiàn)最終渲染并輸出到response的過程虑乖。