DispatcherServlet 是什么
DispatcherServlet本质上就如其名字所展示的那样是一个Java Servlet。同时它是Spring MVC中最为核心的一块——前端控制器。它主要用来拦截符合要求的外部请求,并把请求分发到不同的控制器去处理,根据控制器处理后的结果,生成相应的响应发送到客户端。
DispatcherServlet作为统一访问点,主要进行全局的流程控制。
DispatcherServlet 在web.xml中的配置
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
init-param:初始化参数;
load-on-startup:表示启动容器时初始化该Servlet;
url-pattern:表示哪些请求交给DispatcherServlet(Spring MVC)处理, “/” 是用来定义默认servlet映射的。
DispatcherServlet生命周期:
Servlet的生命周期分为三个阶段:
1,初始化阶段,调用init()方法;
2,响应客户请求阶段,调用service()方法;
3,终止阶段,调用destroy()方法;
下面来看看DispatcherServlet的具体生命周期
DispatcherServlet 初始化
从web.xml中的配置可以知道DispatcherServlet在web容器启动时就进入初始化阶段,调用init()方法。
DispatcherServlet的继承结构:
DispatcherServlet继承自抽象类FrameworkServlet,间接继承了HttpServlet(FrameworkServlet继承自HttpServletBean,HttpServletBean继承自HttpServlet)
DispatcherServlet初始化的方法调用关系
从上图可以清晰的看到DispatcherServlet初始化时方法的调用情况
1).调用HttpServlet的init()方法
主要作用:将Servlet初始化参数(init-param)设置到该组件上(如contextAttribute、contextClass、namespace、contextConfigLocation)
public final void init() throws ServletException {
// 日志处理代码
try {
//将Servlet初始化参数设置到该组件上
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
} catch (BeansException ex) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
throw ex;
}
// 调用FrameworkServlet的initServletBean()方法(该方法由FrameworkServlet重写)
initServletBean();
// 日志处理代码
}
2).调用FrameworkServlet的initServletBean()和initWebApplicationContext()方法
主要作用:初始化web上下文
protected final void initServletBean() throws ServletException {
// 日志处理代码
try {
//调用initWebApplicationContext()方法
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
//异常处理
// 日志处理代码
}
protected WebApplicationContext initWebApplicationContext() {
// 初始化上下文
if (!this.refreshEventReceived) {// if条件确保onRefresh只执行一次
// 调用DispatcherServlet的onRefresh()方法(该方法由DispatcherServlet重写)
onRefresh(wac);
}
//省略部分代码
}
3).调用DispatcherServlet的onRefresh()和initStrategies()方法
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);// 文件上传解析,用于支持文件上传,默认为null
initLocaleResolver(context);// 本地化解析,默认为AcceptHeaderLocaleResolver
initThemeResolver(context);// 主题解析,通过它来实现一个页面多套风格,默认为FixedThemeResolver
initHandlerMappings(context);// 通过HandlerMapping,将请求映射到处理器,详见下文默认值配置
initHandlerAdapters(context); // 通过HandlerAdapter支持多种类型的处理器,详见下文默认值配置
initHandlerExceptionResolvers(context);// 如果执行过程中遇到异常将交给HandlerExceptionResolver来解析
initRequestToViewNameTranslator(context);// 当处理器没有返回视图名时,直接解析请求URL作为视图名,默认为DefaultRequestToViewNameTranslator
initViewResolvers(context);// 解析逻辑视图名到具体视图实现,默认为InternalResourceViewResolver
initFlashMapManager(context);// flash映射管理器,默认为SessionFlashMapManager
}
至此DispatcherServlet的初始化完成。
从上面的过程可以看出DispatcherServlet的初始化主要做了两件事:
1.初始化Spring Web MVC使用的Web上下文;
2.初始化DispatcherServlet使用的策略。
DispatcherServlet使用策略默认值
在DispatcherServlet同一个包下有一个DispatcherServlet.properties配置文件,里面配置了DispatcherServlet一些组件的默认值
spring-webmvc-4.1.4.RELEASE的默认配置如下:
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
注:HandlerMapping和HandlerAdapter的默认值DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter从3.2版本开始已弃用
DispatcherServlet 响应请求
FrameworkServlet定义了Servlet的service()方法
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String method = request.getMethod();
if (method.equalsIgnoreCase(RequestMethod.PATCH.name())) {
processRequest(request, response);
} else {
super.service(request, response);
}
}
无论请求方式是GET、POST、PUT……下一步都会调用FrameworkServlet的processRequest()方法。
以GET为例
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
initContextHolders(request, localeContext, requestAttributes);
try {
// 调用DispatcherServlet的doService()方法
doService(request, response);
} catch (ServletException ex) {
failureCause = ex;
throw ex;
} catch (IOException ex) {
failureCause = ex;
throw ex;
} catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
//日志处理代码
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
最终调用DispatcherServlet的doService()方法,doService()方法中再调用核心的doDispatch()分派方法完全请求的处理。
关于DispatcherServlet的doDispatch()请参考:http://blog.csdn.net/yangshen_/article/details/53573271
DispatcherServlet 销毁
调用destroy()方法,该方法由FrameworkServlet实现。
/**
* Close the WebApplicationContext of this servlet.
*
* @see org.springframework.context.ConfigurableApplicationContext#close()
*/
@Override
public void destroy() {
getServletContext().log("Destroying Spring FrameworkServlet '" + getServletName() + "'");
// Only call close() on WebApplicationContext if locally managed...
if (this.webApplicationContext instanceof ConfigurableApplicationContext
&& !this.webApplicationContextInjected) {
((ConfigurableApplicationContext) this.webApplicationContext).close();
}
}