SpirngMVC源码分析
分析过程
通过 前端控制器源码 分析 SpringMVC 的执行过程
前端控制器在 web.xml 文件中的配置
<!-- springmvc 前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- contextConfigLocation配置springmvc加载的配置文件(配置处理器映射器、适配器等等)
如果不配置contextConfigLocation,默认加载的是 WEB-INF/servlet名称-servlet.xml (即springmvc-servlet.xml)
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!--
第一种:*.action,访问以.action结尾的由DispatcherServlet进行解析
第二种: /,所有访问地址都由DispatcherServlet进行解析
但是对于静态文件的解析,我们需要配置不让DispatcherServlet进行解析
使用此种方式可以实现Restful风格的URL
第三种: /* 这种配置不对,使用这种配置,最终要转发到一个jsp页面时,仍然会由DispatcherServlet
解析jsp,不能根据jsp页面找到Handler,会报错。
-->
<url-pattern>*.action</url-pattern>
</servlet-mapping>
第一步:前端控制器接收请求
调用doDispatch
第二步:前端控制器 调用 处理器映射器 查找 Handler
(1)
(2)映射器根据 request 中的 URL 找到了 Handler,最后返回了执行器链(链中有 Handler)
第三步:调用 处理器适配器 执行 Handler,得到执行的结果ModelAndView
第四步:视图渲染,将 Model 的数据填充到 request 域
(1)获取 ModelAndView 之后,调用 processDispatchResult()方法
(2)processDispatchResult()方法中的 render 方法进行视图渲染
(3)render方法进行视图解析,得到 view。view继续调用其 redner()方法。
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.resolveLocale(request);
response.setLocale(locale);
View view;
if (mv.isReference()) {
// We need to resolve the view name.
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 {
// 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 {
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;
}
}
(4)然后我们发现 render()方法是 View 接口中的一个方法。
(5)我们继续向下找,找到实现 View 接口的抽象类 AbstractView。
抽象类 AbstractView 中,有 render 方法,render 方法中有 renderMergedOutputModel()方法———渲染合并后的输出模型方法
(6)在 AbstractView 抽象类的子类的 renderMergedOutputModel()方法(以InternalResourceView类为例)中,调用了父类的 exposeModelAsRequestAttributes()这个方法。
(7)在 exposeModelAsRequestAttributes()这个方法中,循环遍历 Model ,一个一个填充到 Request 域中(即将模型数据填充 到Request域中)
博主水平有限,如有错误之处,请多多批评指正。原创文章,转载或复制请点个赞再走哦(赠人玫瑰,手有余香~~~)