DispatcherServlet类源码简介说明

java-教程王 SpringMVC 发布时间:2021-12-15 21:44:22 阅读数:16656 1
下文是笔者分享DispatcherServlet类的相关简介说明,如下所示:
DispatcherServlet -->FrameworkServlet 
FrameworkServlet-->HttpServletBean 和 Applicationlistener
ApplicationListener-->EventListener
HttpServletBean-->HttpServlet-->GenericServlet....

DispatcherServlet类的运行方式

通过父类预留的方法,最终运行onRefres方法,
然后进入加载操作
如:
@Override  
protected void onRefresh(ApplicationContext context) {  
	initStrategies(context);  
}  

/** 
 * 初始化定位解析器、主题解析器、
 处理器映射器、处理器适配器、
 异常解析器、视图解析器等等
 */  
protected void initStrategies(ApplicationContext context) {  
	initMultipartResolver(context);  
	initLocaleResolver(context);  
	initThemeResolver(context);  
	initHandlerMappings(context);  
	initHandlerAdapters(context);  
	initHandlerExceptionResolvers(context);  
	initRequestToViewNameTranslator(context);  
	initViewResolvers(context);  
	initFlashMapManager(context);  
} 

processRequest()方法

@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;  
  
    // Expose current LocaleResolver and request as LocaleContext.  
    LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();  
    LocaleContextHolder.setLocaleContext(buildLocaleContext(request), this.threadContextInheritable);  
  
    // Expose current RequestAttributes to current thread.  
    RequestAttributes previousRequestAttributes = RequestContextHolder.getRequestAttributes();  
    ServletRequestAttributes requestAttributes = null;  
    if (previousRequestAttributes == null || previousRequestAttributes.getClass().equals(ServletRequestAttributes.class)) {  
        requestAttributes = new ServletRequestAttributes(request);  
        RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);  
    }  
  
    if (logger.isTraceEnabled()) {  
        logger.trace("Bound request context to thread: " + request);  
    }  
  
    try {  
        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 {  
        // Clear request attributes and reset thread-bound context.  
        LocaleContextHolder.setLocaleContext(previousLocaleContext, this.threadContextInheritable);  
        if (requestAttributes != null) {  
            RequestContextHolder.setRequestAttributes(previousRequestAttributes, this.threadContextInheritable);  
            requestAttributes.requestCompleted();  
        }  
        if (logger.isTraceEnabled()) {  
            logger.trace("Cleared thread-bound request context: " + request);  
        }  
  
        if (logger.isDebugEnabled()) {  
            if (failureCause != null) {  
                this.logger.debug("Could not complete request", failureCause);  
            }  
            else {  
                this.logger.debug("Successfully completed request");  
            }  
        }  
        if (this.publishEvents) {  
            // Whether or not we succeeded, publish an event.  
            long processingTime = System.currentTimeMillis() - startTime;  
            this.webApplicationContext.publishEvent(  
                    new ServletRequestHandledEvent(this,  
                            request.getRequestURI(), request.getRemoteAddr(),  
                            request.getMethod(), getServletConfig().getServletName(),  
                            WebUtils.getSessionId(request), getUsernameForRequest(request),  
                            processingTime, failureCause));  
        }  
    }  
}
DispatcherServlet也是通过自己的service()方法
来接收和转发Http请求到具体的doGet()或doPost()这些方法的
例:一个GET请求为例
  经过HttpServlet基类中service()方法的委派
  请求会被转发到doGet()方法中
 doGet()方法,在DispatcherServlet的父类FrameworkServlet类中被覆写。

processRequest()方法理解的要点是以doService()方法为区隔,
前一部分是将当前请求的Locale对象和属性,
分别设置到LocaleContextHolder和RequestContextHolder这两个抽象类中的ThreadLocal对象中,
也就是分别将这两个东西和请求线程做了绑定
在doService()处理结束后,再恢复回请求前的LocaleContextHolder和RequestContextHolder
也即解除线程绑定。
每次请求处理结束后,容器上下文都发布了一个ServletRequestHandledEvent事件,你可以注册监听器来监听该事件。
可以看到,processRequest()方法只是做了一些线程安全的隔离,真正的请求处理,发生在doService()方法中。

doService()方法

@Override  
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {  
	if (logger.isDebugEnabled()) {  
		String requestUri = urlPathHelper.getRequestUri(request);  
		logger.debug("DispatcherServlet with name '" + getServletName() + "' processing " + request.getMethod() +  
				" request for [" + requestUri + "]");  
	}  

	// Keep a snapshot of the request attributes in case of an include,  
	// to be able to restore the original attributes after the include.  
	Map attributesSnapshot = null;  
	if (WebUtils.isIncludeRequest(request)) {  
		logger.debug("Taking snapshot of request attributes before include");  
		attributesSnapshot = new HashMap();  
		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.  
	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));  
	}  
	request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());  
	request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);  

	try {  
		doDispatch(request, response); //这边最终也是调用了doDispatch方法,该方法主要用来处理SPring框架的具体业务分发逻辑。  
	}  
	finally {  
		// Restore the original attribute snapshot, in case of an include.  
		if (attributesSnapshot != null) {  
			restoreAttributesAfterInclude(request, attributesSnapshot);  
		}  
	}  
}
doService()方法中requet.setAttribute()方法的调用,
将前面在初始化流程中实例化的对象设置到http请求的属性中,
供下一步处理使用,
其中有容器的上下文对象、本地化解析器等SpringMVC特有的编程元素
不同于Struts2中的ValueStack,SpringMVC的数据并没有从HttpServletRequest对象中
抽离出来再存进另外一个编程元素,
这也跟SpringMVC的设计思想有关。
因为从一开始,SpringMVC的设计者就认为,
不应该将请求处理过程和Web容器完全隔离
所以,真正发生请求转发的方法doDispatch()中,
它的参数是HttpServletRequest和HttpServletResponse对象。

doDispatch()方法

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  
	HttpServletRequest processedRequest = request;  
	HandlerExecutionChain mappedHandler = null;  
	int interceptorIndex = -1;  

	try {  
		ModelAndView mv;  
		boolean errorView = false;  

		try {  
			processedRequest = checkMultipart(request);  

			// Determine handler for the current request.  
			mappedHandler = getHandler(processedRequest, false);  
			if (mappedHandler == null || mappedHandler.getHandler() == null) {  
				noHandlerFound(processedRequest, response);  
				return;  
			}  

			// 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();  
			boolean isGet = "GET".equals(method);  
			if (isGet || "HEAD".equals(method)) {  
				long lastModified = ha.getLastModified(request, mappedHandler.getHandler());  
				if (logger.isDebugEnabled()) {  
					String requestUri = urlPathHelper.getRequestUri(request);  
					logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);  
				}  
				if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {  
					return;  
				}  
			}  

			// 这里是处理前置拦截器  
			HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();  
			if (interceptors != null) {  
				for (int i = 0; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors[i]; if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) { triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null); return; } interceptorIndex = i; } } //处理最终的Action逻辑 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // Do we need view name translation? if (mv != null && !mv.hasView()) { mv.setViewName(getDefaultViewName(request)); } //处理后置拦截器 if (interceptors != null) { for (int i = interceptors.length - 1; i >= 0; i--) {  
					HandlerInterceptor interceptor = interceptors[i];  
					interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);  
				}  
			}  
		}  
		catch (ModelAndViewDefiningException ex) {  
			logger.debug("ModelAndViewDefiningException encountered", ex);  
			mv = ex.getModelAndView();  
		}  
		catch (Exception ex) {  
			Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);  
			mv = processHandlerException(processedRequest, response, handler, ex);  
			errorView = (mv != null);  
		}  

		// Did the handler return a view to render?  
		if (mv != null && !mv.wasCleared()) {  
			render(mv, processedRequest, response);  
			if (errorView) {  
				WebUtils.clearErrorRequestAttributes(request);  
			}  
		}  
		else {  
			if (logger.isDebugEnabled()) {  
				logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +  
						"': assuming HandlerAdapter completed request handling");  
			}  
		}  

		// Trigger after-completion for successful outcome.  
		triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);  
	}  

	catch (Exception ex) {  
		// Trigger after-completion for thrown exception.  
		triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);  
		throw ex;  
	}  
	catch (Error err) {  
		ServletException ex = new NestedServletException("Handler processing failed", err);  
		// Trigger after-completion for thrown exception.  
		triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);  
		throw ex;  
	}  

	finally {  
		// Clean up any resources used by a multipart request.  
		if (processedRequest != request) {  
			cleanupMultipart(processedRequest);  
		}  
	}  
}
doDispatch()是整个请求转发流程中最核心的方法
DispatcherServlet所接收的Http请求,
经过层层转发,
最终都是汇总到这个方法中来进行最后的请求分发和处理。
它通过高度抽象的接口,描述出了一个MVC(Model-View-Controller)设计模式的实现方案
Model、View、Controller三种层次的编程元素,
在SpringMVC中都有大量的实现类,各种处理细节也是千差万别。
但是,它们最后都是由,也都能由doDispatch()方法来统一描述,
这就是接口和抽象的威力,万变不离其宗。
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

本文链接: https://www.Java265.com/JavaFramework/SpringMVC/202112/2085.html

最近发表

热门文章

好文推荐

Java265.com

https://www.java265.com

站长统计|粤ICP备14097017号-3

Powered By Java265.com信息维护小组

使用手机扫描二维码

关注我们看更多资讯

java爱好者