SpringMVC运行流程:
4和5版本都差不多,只是中间的过程有点差别,前面的源码分析有点乱,以这篇为准
1、所有请求,前端控制器(DispatcherServlet)收到请求,调用doDispatch进行处理
2、根据HandlerMapping中保存的请求映射信息找到,处理当前请求的,处理器执行链(包含拦截器)
3、根据当前处理器找到他的HandlerAdapter(适配器)
4、拦截器的preHandle先执行
5、适配器执行目标方法,并返回ModelAndView
1)、ModelAttribute注解标注的方法提前运行
2)、执行目标方法的时候(确定目标方法用的参数)
1)、有注解
1)、请求参数注解
2)、ModelAttribute;sessionAttribute注解,
1)、只有ModelAttribute注解,有就拿,拿不到就新建
2)、sessionAttribute注解中也有,那么拿得到就拿,拿不到就抛异常
2)、没注解:
1)、 看是否Model、Map以及其他的
2)、如果是自定义类型
1)、从隐含模型中看有没有,如果有就从隐含模型中拿
2)、如果没有,再看是否SessionAttributes标注的属性,
如果是从Session中拿,如果拿不到会抛异常
3)、都不是,就利用反射创建对象
6、拦截器的postHandle执行
7、处理结果;(页面渲染流程)
1)、如果有异常使用异常解析器处理异常;处理完后还会返回ModelAndView
2)、调用render进行页面渲染
1)、视图解析器根据视图名得到视图对象
2)、视图对象调用render方法;
3)、执行拦截器的afterCompletion;
SpringMVC与Spring整合
web.xml
<display-name>Archetype Created Web Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--SpringMVC思想是有一个前端控制器能拦截所有请求,并智能派发
前端控制器是一个Servlet;应该在web.xml配置
-->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--
servlet启动加载,servlet原本是第一次访问创建对象;
load-on-startup:服务器启动时创建对象;值越小优先级越高
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<!--
/*和/都是拦截所有请求;/:会拦截所有请求,但是不会拦截*.jsp;保证jsp访问正常;
/*:的范围更大;会拦截*.jsp;一旦拦截jsp页面就不能正常显示
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
在web.xml中,一般会指定两个容器,一个是Spring的,一个是SpringMVC的。分别是上述代码的第一第二个。
Spring在启动的时候,会加载两个容器。
目的
SpringMVC和Spring整合的目的;分工明确;
SpringMVC的配置文件就来配置和网站转发逻辑以及网站功能有关的
(视图解析器,文件上传解析器,支持ajax,xxx);
Spring的配置文件来配置和业务有关的(事务控制,数据源,xxx);
带来的问题
Spring是一个父容器,SpringMVC是一个子容器;
子容器还可以引用父容器的组件;
父容器不能引用子容器的组件;
即:假设你的controller是在SpringMVC配置文件中扫描的,你的service是在Spring配置文件扫描,那么
你就不能在service中注入Controller。