SpringMVC的基本运行流程
先通过一张图片来了解SpringMVC的基本流程
具体的执行流程:
- 客户端向服务器端发送url请求,请求被前端控制器捕获(通过Servlet-mapping中的url-pattern标签设置)
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得HandlerExecutionChain对象(包含了Handler对象以及Handler对象对应的拦截器)并返回。
3. DispatcherServlet 根据获得的**Handler(对Controller的Bean本身和请求Method的包装)**,选择一个合适的HandlerAdapter。(**附注**:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法)
4. Handler执行完毕后会返回给前端控制器一个ModelAndView对象。
5. 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)来解析View对象并返回给前端控制器。
6. 根据view对象和model对象渲染前端页面并返回给前端控制器。
7. 前端控制器返回页面给客户端。
通过一个简单的例子来说明执行流程
1.index.jsp
<script>
top.location.href = "toLogin.do";
</script>
2.web.xml
<!-- 配置SpringMVC -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 指定SpringMVC配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
jsp页面发送toLogin.do的请求,前端控制器通过<url-pattern>*.do</url-pattern>
截取到请求,加载指定的配置文件springmvc-config.xml。
3.springmvc-config.xml
<!-- MVC注解驱动 -->
<mvc:annotation-driven/>
<!-- 配置扫描器,使得@Controller注解生效 -->
<context:component-scan base-package="com.ty.epms.controller" />
<!-- 定义视图解析器 -->
<!-- prefix="/WEB-INF/jsp/", suffix=".jsp", viewname="test" -> "/WEB-INF/jsp/test.jsp" -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 后缀 -->
<property name="suffix" value=".jsp" />
</bean>
加载配置文件之后会扫描@Controller注解,<mvc:annotation-driven/>
注解方式配置处理器映射器和处理器适配器,也可以手动配置就和视图解析器一样。
4.UserController.java
@Controller
public class UserController {
@Autowired
UserService userService;
@RequestMapping("/toLogin")
public String toLogin() {
return "login";
}
}
通过@RequestMapping("/toLogin")执行下面的方法,此时就已经返回了handler对象,接下来执行这个handler,我这里并没有设置Model对象,返回的是View(return “login”),这个过程会被试图解析器解析这个view并渲染,然后通过DsipatcherServlet返回给客户端。
Spring工作流程描述
1.为什么Spring只使用一个Servlet(DispatcherServlet)来处理所有请求?
详细见J2EE设计模式-前端控制模式
2.Spring为什么要结合使用HandlerMapping以及HandlerAdapter来处理Handler?
符合面向对象中的单一职责原则,代码架构清晰,便于维护,最重要的是代码可复用性高。如HandlerAdapter可能会被用于处理多种Handler