总结:
1、用户发起请求,到前端控制器(DispatchServlet),会执行到(doDispatch)方法;
2、循环 HandlerMapping 查找 Handler,返回一个处理器执行链(HandlerExecutionChain);
HandlerExecutionChain 包含:
a)Handler对象
b) HandlerInterceptor[] 拦截器数组
4、通过HandlerAdapter进行包装Handler,返回一个HandlerAdapter对象;
5、循环执行处理器执行链中拦截器的前置方法;
6、通过适配器执行Handler,返回一个ModelAndView;
a)Model Data(模型数据)
b)View(ViewName) 视图名称
7、DispatcherServlet将ModelAndView传给ViewReslover视图解析器;
8、ViewReslover解析后返回具体View;
9、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中);
10、DispatcherServlet响应用户。
简单总结:
1、请求进入中央处理器(DispatcherServlet)
2、通过HandlerMapping查询业务逻辑类
3、通过HandlerAdapter执行业务逻辑
4、通过ViewReslover渲染视图
5、DispatcherServlet响应用户
为什么要设计适配器?
适配器是专门用来执行业务方法的,业务方法的Controller有很多种类型,如果没有适配器的话,在DispatcherServlet中调用Controller中业务方法的时,需要判断Controller类型后再调用;如果这是我们想扩展一个自己的Controller,是需要改源码做判断调用。违反扩展开放,修改关闭的原则。如果有个适配器,这时要扩展Contrller,只需要编写自己的Controller和实现适配器接口就可以了。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.springmvcgroupId>
<artifactId>SpringMVCTestartifactId>
<version>1.0.0-SNAPSHOTversion>
<packaging>warpackaging>
<properties>
<junit.version>4.10junit.version>
<slf4j.version>1.6.4slf4j.version>
<spring.version>4.1.3.RELEASEspring.version>
<jstl.version>1.2jstl.version>
<servlet-api.version>2.5servlet-api.version>
<jsp-api.version>2.0jsp-api.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
<version>${slf4j.version}version>
dependency>
<dependency>
<groupId>jstlgroupId>
<artifactId>jstlartifactId>
<version>${jstl.version}version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>servlet-apiartifactId>
<version>${servlet-api.version}version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jsp-apiartifactId>
<version>${jsp-api.version}version>
<scope>providedscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.mavengroupId>
<artifactId>tomcat7-maven-pluginartifactId>
<configuration>
<port>80port>
<path>/path>
configuration>
plugin>
plugins>
build>
project>
在src/main/webapp下创建WEB-INF目录以及web.xml
配置DispatcherServlet
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>spingmvcdisplay-name>
<servlet>
<servlet-name>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<load-on-startup>1load-on-startup>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc-servlet.xmlparam-value>
init-param>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>*.dourl-pattern>
servlet-mapping>
web-app>
在src/main/resources下创建log4j.properties
log4j.rootLogger=DEBUG,A1
log4j.logger.org.mybatis = DEBUG
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n
在src/main/resources下创建springmvc-servlet.xml
SpringMVC默认从WEB-INF下读取servlet配置文件,文件的命名规则是:servletName-servlet.xml
如果要自定义servlet文件,需要在servlet定义时指定contextConfigLocation。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<bean name="/hello.do" class="com.springmvc.handler.HelloHandler"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
bean>
beans>
配置文件解析:
1、配置处理器映射器HandlerMapping
2、配置处理器适配器HandlerAdapter
3、配置模型Handler
4、配置视图解析器ViewResolver
HandlerMapping:
HandlerAdapter:
ViewResolver:
Controller是多种类型的,如果没有适配器,在DispatcherServlet中调用Hadnler,需要判断Controller类型做调用,我们想去扩展自己的Controller,需要去改源码做判断调用。违反开闭(对扩展开放,对修改关闭)原则。
如果有了适配器,如果要扩展Controller,只需要写自己的Controller和实现适配器接口即可。
package com.springmvc.handler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
public class HelloHandler implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 处理业务逻辑
ModelAndView mv = new ModelAndView();
mv.setViewName("hello");// 设置视图名称
mv.addObject("msg", "我的第一个SpringMVC应用!");// 设置模型数据
// request.setAttribute("msg", "xxxxx");
return mv;
}
}
DispatcherServlet源码初始化过程
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context); //文件上传组件
initLocaleResolver(context); //国际化
initThemeResolver(context);// 主题
initHandlerMappings(context);// HandlerMapping 处理器映射
initHandlerAdapters(context);// HandlerAdapter 适配器
initHandlerExceptionResolvers(context); //异常相关组件
initRequestToViewNameTranslator(context); // 转化
initViewResolvers(context); // ViewResolvers 视图解析器
initFlashMapManager(context); // 闪存
}
初始化映射器
初始化适配器
SpringMVC的默认配置文件
org.springframework.web.servlet.DispatcherServlet.properties
发现默认的配置文件中已经配置了默认的映射器和适配器,所以可以简化配置,无需配置映射器和适配器。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
// 定义执行链
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
// 获取执行链
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 获取Handler的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 执行链中拦截器的前置方法,如果返回false则终止执行。
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
// Actually invoke the handler.
// 通过Handler适配器执行Handler
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
applyDefaultViewName(request, mv);
// 执行拦截器的后置方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
// 处理返回的结果,视图解析器的处理
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
}
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
// 1、定义执行处理器执行链(HandlerExecutionChain mappedHandler = null;)
// 2、获取处理器执行链(mappedHandler = getHandler(processedRequest);)
// 3、获取处理器适配器(HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());)
// 4、执行链中拦截器的前置方法,如果返回false则终止执行(if (!mappedHandler.applyPreHandle(processedRequest, response)))
// 5、通过适配器执行真正的业务处理器逻辑,并返回模型和视图对象(mv = ha.handle(processedRequest, response, mappedHandler.getHandler());)
// 6、执行链中拦截器的后置方法(mappedHandler.applyPostHandle(processedRequest, response, mv);)
// 7、处理返回的结果,视图解析器的处理(processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);)
// 8、查找到视图后进行渲染,然后响应给请求端
在第一个SpringMVC应用的基础上修改SpringMVC配置文件和编写模型对象处理器。
下面两个配置不是SpringMVC默认配置,所以不能省略。
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<context:component-scan base-package="com.springmvc.handler" />
使用@RequestMapping映射请求URL
使用@Controller注解使HelloHandler 成为处理请求的控制器
package com.springmvc.handler;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/hello")
public class HelloHandler {
@RequestMapping("/show")
public ModelAndView show() {
// 处理业务逻辑
ModelAndView mv = new ModelAndView();
mv.setViewName("hello");// 设置视图名称
mv.addObject("msg", "我的第一个注解SpringMVC应用!");// 设置模型数据
return mv;
}
}
作用:SpringMVC默认配置的升级版;
<mvc:annotation-driven />
对应的java类是:
org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser
使用
HandlerMapping有2个:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
Adapter有3个:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter