1. SpringMVC 运行流程
- 请求过来,前端控制器 (DispatcherServlet) 调用 doDispatcher() 进行处理
- 根据 HandlerMapping 中保存的请求映射信息找到处理当前请求的「处理器执行链 (HandlerExecutionChain = Handler + Interceptor)」
- 根据当前处理器找到它的适配器(HandlerAdapter)
- 拦截器的 preHandle 顺序执行
- 适配器执行目标方法
→ @ModelAttribute 标注的方法提前运行 → 确定目标方法用的参数 → 有注解 → 无注解 → 是否是 ServletAPI → 是否是 Model / Map 类型 → 是否自定义类型 → 看隐含模型中是否有同名的,有就赋值 → 如果没有,看是否是 @SessionAttributes 标注的属性 → 如果都不是,利用反射创建对象 → 执行目标方法,返回 ModelAndView
- 拦截器的 postHandle 逆序执行
- 处理结果(页面渲染过程)
→ 若有异常,使用异常解析器(HandlerExceptionResolver) 处理异常,然后返回 mav → 调用 render() 进行页面渲染 → 视图解析器根据视图名得到视图对象 → 视图对象调用 render() 完成渲染
- 拦截器的 afterCompletion 逆序执行
2. 与 Spring 整合
目的:分工明确
- SpringMVC 的配置文件就来配置和网站转发逻辑以及网站功能有关的(各种解析器、支持 Ajax ...)
- Spring 的配置文件来配置和业务有关的(事务控制、数据源 ...)
Spring 和 SpringMVC 分容器:
- springMVC.xml (管理控制器组件)
<context:component-scan base-package="cn.edu.nuist" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/> </context:component-scan>
- spring.xml (管理业务逻辑组件)
<context:component-scan base-package="cn.edu.nuist" use-default-filters="true"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/> </context:component-scan>
- web.xml
<!-- Spring 容器 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- SpringMVC 容器 --> <servlet> <servlet-name>springDispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springMVC.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <!-- Map all requests to the DispatcherServlet for handling --> <servlet-mapping> <servlet-name>springDispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
启动 Server 时的控制台打印:
SpringMVC 的 IOC 容器中的 bean 可以来引用 Spring IOC 容器中的 bean,返回来呢 ?
- 反之则不行!Spring IOC 容器中的 bean 不能来引用 SpringMVC IOC 容器中的 bean!
- 多个 Spring IOC 容器之间可以设置为父子关系,以实现良好的解耦。
- Spring MVC 配置文件中引用业务层的 bean,故 SpringMVC Web 层容器可作为 "业务层" Spring 容器的子容器:即 Web 层容器可以引用业务层容器的 bean,而业务层容器却访问不到 Web 层容器的 bean。