一.DispatcherServlet简述
DispatcherServlet
是Spring MVC
框架中的前端控制器,通过调度其他组件来处理用户的请求,因此可以说它是Spring MVC中最核心的部分。
二.分析思路
在分析前,我们应该首先明确分析的思路和过程。从名字中我们可以很容易知道,DispatcherServlet
首先是一个Servlet
,因此它被配置在web.xml
文件中。而我们分析一个Sevlet,通常的思路应当是顺着其生命周期分析。
– init方法
– service方法
– destory方法
三.init方法
1. 找到init方法
直接在DispatcherServlet
中并没有找到init()
方法,但是发现该类继承自其他类,这是它的继承关系图。
通过向父类中寻找可以发现是HttpServletBean这个类重写了init方法,跳转到HttpServletBean
这个类中
2. init方法剖析
– 源码展示
public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
}
try {
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;
}
initServletBean();
if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}
这个方法和核心涉及到三个类,PropertyValues
,BeanWrapper
,和ResourceLoader
,因此我们应该分别分析这三个类的实例对象在该方法起到的作用
PropertyValues
PropertyValues
是HttpServletBean的一个内部类,继承了MutablePropertyValues
,用来获取web.xml中的属性如contextConfigLocation
。BeanWrapper
BeanWrapper
封装了bean的行为,提供了设置和获取属性值。ResourceLoader
ResourceLoader
用来获取spring mvc配置文件的信息
先通过PropertyValues获取web.xml文件init-param的参数值,然后通过ResourceLoader读取.xml配置信息,BeanWrapper对配置的标签进行解析和将系统默认的bean的各种属性设置到对应的bean属性
注意到第17行的initServletBean()
方法,这是一个抽象方法,在源代码中作者的注释为Let subclasses do whatever initialization they like.
即要求子类实现这个方法去完成子类还需要的其他初始化操作,通过代码的跟踪,我们可以在DispatcherSevlet方法中找到一个方法为initStrategies()
,这个方法就是子类为初始化工作编写的代码,该方法代码如下。
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
- 一开始我们说到DispatcherServlet是通过调度其他组件来处理请求的,因此该类必定要对那些组件进行初始化,而这段代码就是进行这样的工作的。我们从此也可以知道DispatcherServlet依赖了什么组件。
- MultipartResolver
- LocaleResolver
- ThemeResolver
- HandlerMappings
- HandlerAdapters
- HandlerExceptionResolvers
- RequestToViewNameTranslator
- ViewResolvers
- FlashMapManager
四.Service方法
在Servlet中,每个请求都会被对应的Servlet类中的service方法处理,在DispatcherServlet中,service的实现在其父类FrameworkServlet
中
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);
}
}
其核心的方法是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 {
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();
}
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");
}
}
}
publishRequestHandledEvent(request, startTime, failureCause);
}
}
这个方法执行的核心方法为doService
,doService
是一个抽象方法,在DispatcherServlet中实现
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
" 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<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
logger.debug("Taking snapshot of request attributes before include");
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.
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);
}
finally {
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
return;
}
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
但是控制器和拦截器的代码是在doDispach()
中执行的
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;
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
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;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
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()) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
}
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
- 说明
- 第33行的
mappedHandler.applyPreHandle(processedRequest, response)
执行的是拦截器中的pre…方法 - 第37行的
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
执行的是控制器中的方法,返回值是一个ModelAndView
- 第46行的
mappedHandler.applyPostHandle(processedRequest, response, mv);
执行拦截器中的post…方法 - 第51行的
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
中的mappedHandler.triggerAfterCompletion(request, response, null);
执行affter…方法. - 第51行的
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
中的render(mv, request, response);
渲染对应视图的
- 第33行的
destory方法在Dispatcher中并不重要,因此在此不做分析。
总结
本章节以分析一个Servlet的方式找到了DispatcherServlet的init方法和service方法,简单的描绘了一个servlet的生命周期,在初始化过程中先对各个组件进行初始化,当用户请求过来时,通过service方法处理,分别执行拦截器中的方法和对应控制器中的方法。