接上一篇文章 说明了url和具体controller方法的缓存和处理请求时的执行逻辑,这里我们跟一下执行完成后页面渲染的逻辑,代码接着上一篇(调用栈):
org.springframework.web.servlet.DispatcherServlet#doDispatch
|
org.springframework.web.servlet.DispatcherServlet#processDispatchResult
|
org.springframework.web.servlet.DispatcherServlet#render
页面渲染方法入口就是 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 != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
View view;
String viewName = mv.getViewName();
//@A
if (viewName != null) {
// We need to resolve the view name.
view = resolveViewName(viewName, 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 {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
//@B
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;
}
}
- @A:获得一个view,这个view就是我们在mvc配置文件里配置的 viewResolver 解析来的view,是一个 InternalResourceView 对象
- @B:调用view的render方法,实则会执行 org.springframework.web.servlet.view.AbstractView#render方法,然后调用子类的方法
org.springframework.web.servlet.view.InternalResourceView#renderMergedOutputModel
@Override
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
//@C
// Expose the model object as request attributes.
exposeModelAsRequestAttributes(model, request);
// Expose helpers as request attributes, if any.
exposeHelpers(request);
// Determine the path for the request dispatcher.
String dispatcherPath = prepareForRendering(request, response);
//@D
// Obtain a RequestDispatcher for the target resource (typically a JSP).
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 already included or response already committed, perform include, else forward.
if (useInclude(request, response)) {
response.setContentType(getContentType());
if (logger.isDebugEnabled()) {
logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
}
rd.include(request, response);
}
else {
// Note: The forwarded resource is supposed to determine the content type itself.
if (logger.isDebugEnabled()) {
logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
}
//@E
rd.forward(request, response);
}
}
- @C:调用 request.setAttribute(modelName, modelValue);方法将model里的存放的key,value值全部放到request中
- @D:通过jsp路径获得RequestDispatcher 对象
- @E:调用RequestDispatcher的forward转向到对应的输出(这个是不是很熟悉)