DispatcherServlet的作用
上面是网上找的一张图,大概可以说明DispatcherServlet在整个数据流中起到的作用。
- 初始化springmvc所需的组件
- 截获请求,交给springmvc框架处理
- 协调组件处理请求
本文不注重细节的分析,只简单分析下是如何截获http请求和如何协调组件进行处理http请求
将请求交予springmvc处理的过程
首先看下DispatcherServlet的继承关系:
HttpServlet我们都很熟悉了,对Http请求做了封装。
看下以下几个类:
HttpServletBean
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware
这个类除了继承了HttpServlet,还实现了两个接口,EnvironmentCapable和EnvironmentAware,说明这个类及其子类拥有了获取和设置运行时Environment的能力。
同时,这个类实现了init方法,在servlet初始化时,用来初始化bean。
public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
}
// Set bean properties from init parameters.
try {
//获得web.xml中的contextConfigLocation配置属性,就是spring MVC的配置文件
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()));
//模板方法,可以在子类中调用,做一些初始化工作,bw代表DispatcherServelt
initBeanWrapper(bw);
//将配置的初始化值设置到DispatcherServlet中
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
throw ex;
}
// Let subclasses do whatever initialization they like.
//模板方法,子类初始化的入口方法
initServletBean();
if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}
FrameworkServlet
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware
FrameworkServlet继承了HttpServletBean,同时实现了ApplicationContextAware接口,利用ApplicationContextAware接口的setApplicationContext方法,可以拿到bean容器,ApplicationContext,这个时候FrameworkServlet就有了可以获取容器里所有Bean的能力了。
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
if (this.webApplicationContext == null && applicationContext instanceof WebApplicationContext) {
this.webApplicationContext = (WebApplicationContext) applicationContext;
this.webApplicationContextInjected = true;
}
}
同时FrameworkServlet实现了HttpServlet 的 doGet、doPost等一系列方法,将这些请求移交到processRequest这个方法中处理。
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
下面看下processRequest做了哪些事
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
//获取LocaleContextHolder中存储的原先的LocaleContext【存储Locale信息】
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
//获取当前请求中的LocaleContext
LocaleContext localeContext = buildLocaleContext(request);
//获取RequestContextHolder中存储的原先的RequestAttributes【RequestAttributes是Spring的一个接口,通过该接口可以get/set/removeAttribute】
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
//获取当前请求中的ServletRequestAttributes
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
//使用request获取异步处理管理器
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
//为异步处理管理器注册拦截器
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
//initContextHolders将当前请求的LocaleContext、ServletRequestAttributes设置到LocaleContextHolder、RequestContextHolder【initContextHolders的代码在本代码块后部分】
initContextHolders(request, localeContext, requestAttributes);
try {
//实际处理的方法,在FrameworkServlet只是一个抽象方法由DispatcherServlet来实现【也是DispatcherServlet处理请求的入口】
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 {
//将请求之前的LocaleContext、RequestAttributes恢复到LocaleContextHolder、RequestContextHolder
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
//标记requestActive为false,代表当前请求已完成
requestAttributes.requestCompleted();
}
//日志相关输出
if (logger.isDebugEnabled()) {
if (failureCause != null) {
this.logger.debug("Could not complete request", failureCause);
}
else {
if (asyncManager.isConcurrentHandlingStarted()) {
logger.debug("Leaving response open for concurrent processing");
}
else {
this.logger.debug("Successfully completed request");
}
}
}
//发布ServletRequestHandledEvent消息
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
这个方法主要做了
- 异步请求的处理
- 调用doService方法具体处理请求
- 处理LocaleContext和RequestAttributes
这个doService是一个钩子,会直接调用DispatcherServlet的doService方法。
这里就可以得到请求处理过程的全貌了:
HttpServlet service(ServletRequest req, ServletResponse res)
→FrameworkServlet service(HttpServletRequest request, HttpServletResponse response)
→HttpServlet service(HttpServletRequest req, HttpServletResponse resp)
→FrameworkServlet doGet/doXxxx
→FrameworkServlet processRequest
→DispatcherServlet doService
DispatcherServlet
针对DispatcherServlet,我们看下它的doService方法做了什么。
//获取请求,设置一些request的参数,然后分发给doDispatch
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
}
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<String, Object>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// Make framework objects available to handlers and view objects.
/* 设置web应用上下文**/
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
/* 国际化本地**/
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
/* 样式**/
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
//设置样式资源
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
//请求刷新时保存属性
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
//Flash attributes 在对请求的重定向生效之前被临时存储(通常是在session)中,并且在重定向之后被立即移除
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
//FlashMap 被用来管理 flash attributes 而 FlashMapManager 则被用来存储,获取和管理 FlashMap 实体.
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
try {
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
doService设置了一些属性,然后交予doDispatch方法继续处理,DispatcherServlet的doDispatch方法主要用作职责调度工作,本身主要用于控制流程,也是我们比较关注的一个点,即DispatcherServlet如何协调组件进行处理http请求,源码如下:
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 {
//1、文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析;
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
//2.通过HandlerMapping,将请求映射到处理器(返回一个HandlerExecutionChain,它包括一个处理器、多个HandlerInterceptor拦截器);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
//3、通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器);
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();//得到当前的http方法。
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {//处理http的head方法。这种方法应该很少用
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;
}
}
//4.1调用HandlerExecutionChain的interceptor
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//4.2执行解析handler中的args,调用(invoke) controller的方法。得到视图
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//4.3调用HandlerExecutionChain的interceptor
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
//5.解析视图、处理异常
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
这样请求就处理完成了,具体各个组件是如何进行工作的,后面找时机专门看下。