龙空技术网

SpringMVC—DispatcherServlet解析

她的名字ych 383

前言:

现时同学们对“net调用servlet接口”大概比较注重,朋友们都需要学习一些“net调用servlet接口”的相关知识。那么小编同时在网摘上网罗了一些对于“net调用servlet接口””的相关知识,希望咱们能喜欢,小伙伴们快快来了解一下吧!

DispatcherServlet其实是Servlet接口的实现类,它的本质其实就是一个Servlet。

DispatcherServlet继承图

在讲DispatcherServlet之前,首先介绍一下Servlet的生命周期。

Servlet的生命周期

1. init : 初始化

当Servlet第一次被请求时,服务器就会调用init()方法初始化一个Servlet对象,但是这个方法在后续的请求中不会再次被调用,仅仅只会调用一次。在调用这个方法时,Servlet容器会传入一个ServletConfig对象来对Servlet对象进行初始化。

当发送http请求时:StandardWrapper类会调用allocate()方法给Servlet分配一个初始化的实例。

private synchronized void initServlet(Servlet servlet)            throws ServletException {         // 如果servlet已被初始化,则return        if (instanceInitialized && !singleThreadModel) return;        // Call the initialization method of this servlet        try {            if( Globals.IS_SECURITY_ENABLED) {                boolean success = false;                try {                    Object[] args = new Object[] { facade };                    SecurityUtil.doAsPrivilege("init",                                               servlet,                                               classType,                                               args);                    success = true;                } finally {                    if (!success) {                        // destroy() will not be called, thus clear the reference now                        SecurityUtil.remove(servlet);                    }                }            } else {              // 调用init()方法初始化,facade: 是ServletConfig的实现类              // 这一步会转到DispatcherServlet初始化的过程                servlet.init(facade);            }            instanceInitialized = true;        } catch (UnavailableException f) {            unavailable(f);            throw f;        } catch (ServletException f) {            // If the servlet wanted to be unavailable it would have            // said so, so do not call unavailable(null).            throw f;        } catch (Throwable f) {            ExceptionUtils.handleThrowable(f);            getServletContext().log(sm.getString("standardWrapper.initException", getName()), f);            // If the servlet wanted to be unavailable it would have            // said so, so do not call unavailable(null).            throw new ServletException                (sm.getString("standardWrapper.initException", getName()), f);        }    }

2. service

每次客户端请求这个Servlet时,Servlet容器就会调用service()方法处理请求;在后续的请求中,Servlet容器就只会调用这个方法了。

3. destroy

当服务器关闭或者停止时,Servlet容器就会调用destroy()销毁这个Servlet。

DispatcherServlet初始化

由于DispatcherServlet本质就是一个Servlet,它对Servlet进行了封装,它的生命周期与Servlet一致,当调用init(ServletConfig servletConfig)方法初始化的时候,这个时候采用Java面向对象思想:当子类继承父类时,如果子类没有重写父类的方法,则首先调用父类的方法,它的父类给他做了很多初始化的工作。

由于DispatcherServlet没有重写init(ServletConfig servletConfig)方法,它会找到父类的init(ServletConfig servletConfig)方法,然后调用。

请求流

1. 在其父类GenericServlet类中重写了init(ServletConfig servletConfig)方法

2. 从第一步可以看出DispatcherServlet对象会调用init()初始化方法,由于DispatcherServlet类没有重写init()方法,它会调用父类的init()方法,观察继承结构可知,只有HttpServletBean类重写了init()方法

    @Override    public final void init() throws ServletException {        // ServletConfigPropertyValues 是静态内部类,使用 ServletConfig 获取 web.xml 中配置的参数        PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);        if (!pvs.isEmpty()) {            try {                // 使用 BeanWrapper 来构造 DispatcherServlet                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) {                if (logger.isErrorEnabled()) {                    logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);                }                throw ex;            }        }        // 让子类实现的方法,这种在父类定义在子类实现的方式叫做模版方法模式        initServletBean();    }

3. 从上一步看到,它还要调用initServletBean方法,这个方法在DispatcherServlet类也没有重写,那只能往DispatcherServlet类的父类,HttpServletBean的子类找了,显而易见,只有FrameworkServlet类满足条件

initServletBean():建立 WebApplicationContext 容器(有时也称上下文),并加载 SpringMVC 配置文件中定义的 Bean 到该容器中,最后将该容器添加到 ServletContext 中。

protected WebApplicationContext initWebApplicationContext() {		WebApplicationContext rootContext =				WebApplicationContextUtils.getWebApplicationContext(getServletContext());		WebApplicationContext wac = null;		if (this.webApplicationContext != null) {			// context实例在构造函数中被注入			wac = this.webApplicationContext;			if (wac instanceof ConfigurableWebApplicationContext) {				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;				if (!cwac.isActive()) {					if (cwac.getParent() == null) {						// 将 Spring 的容器设为 SpringMVC 容器的父容器						cwac.setParent(rootContext);					}					//刷新上下文环境					configureAndRefreshWebApplicationContext(cwac);				}			}		}		if (wac == null) {			// 如果 WebApplicationContext 为空,则进行查找,能找到说明上下文已经在别处初始化。			wac = findWebApplicationContext();		}		if (wac == null) {			// 如果servlet仍没有context实例,则以 Spring 的容器为父上下文建立一个新的。			wac = createWebApplicationContext(rootContext);		}		if (!this.refreshEventReceived) {			// Either the context is not a ConfigurableApplicationContext with refresh			// support or the context injected at construction time had already been			// refreshed -> trigger initial onRefresh manually here.			synchronized (this.onRefreshMonitor) {				// 模版方法,由其子类DispatcherServlet 实现				onRefresh(wac);			}		}		if (this.publishContext) {						// 发布这个 WebApplicationContext 容器到 ServletContext 中			String attrName = getServletContextAttributeName();			getServletContext().setAttribute(attrName, wac);		}		return wac;	}

4. 终于,回到我们的子类DispatcherServlet中执行onRefresh(ApplicationContext context)方法中刷新上下文

@Overrideprotected void onRefresh(ApplicationContext context) {   initStrategies(context);}/** * Initialize the strategy objects that this servlet uses. * <p>May be overridden in subclasses in order to initialize further strategy objects. */protected void initStrategies(ApplicationContext context) {   //初始化上传文件解析器(或者是多部分请求解析器)   initMultipartResolver(context);   //初始化本地化解析器   initLocaleResolver(context);   //初始化主题解析器   initThemeResolver(context);   //初始化处理器映射器HandlerMapping  --重点   initHandlerMappings(context);   //初始化处理器适配器   initHandlerAdapters(context);   //初始化处理器异常解析器   initHandlerExceptionResolvers(context);   //初始化请求到视图名翻译器   initRequestToViewNameTranslator(context);   //初始化视图解析器   initViewResolvers(context);   //初始化重定向数据管理器   initFlashMapManager(context);}

下面对处理器映射器HandlerMapping类初始化进行一个说明:

initHandlerMappings() 方法从 SpringMVC 的容器及 Spring 的容器中查找所有的 HandlerMapping 实例,并把它们放入到 handlerMappings 这个 list集合 中。这个方法并不是对 HandlerMapping 实例的创建,HandlerMapping 实例是在上面 WebApplicationContext 容器初始化,即 SpringMVC 容器初始化的时候创建的。

private void initHandlerMappings(ApplicationContext context) {		this.handlerMappings = null;		if (this.detectAllHandlerMappings) {			//从SpringMVC的IOC容器及Spring的IOC容器中查找HandlerMapping实例			Map<String, HandlerMapping> matchingBeans =					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);      if (!matchingBeans.isEmpty()) {				this.handlerMappings = new ArrayList<>(matchingBeans.values());				// 按照一定排序规则放入list中				AnnotationAwareOrderComparator.sort(this.handlerMappings);			}		}		else {			try {				HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);				this.handlerMappings = Collections.singletonList(hm);			}			catch (NoSuchBeanDefinitionException ex) {				// Ignore, we'll add a default HandlerMapping later.			}		}  // 如果没有,则加载默认的  if (this.handlerMappings == null) {			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);			if (logger.isTraceEnabled()) {				logger.trace("No HandlerMappings declared for servlet '" + getServletName() +						"': using default strategies from DispatcherServlet.properties");			}		}}

到此,DispatcherServlet就初始化完成了。

初始化完成

然后,调用service方法开始处理http请求。

下面,主要讲DispatcherServelt如何处理请求,并封装结果响应。

DispatcherServelt处理请求

在分析处理请求之前,先看一下总体流程:

DispatcherServlet处理请求流程

下面是更加详细的版本

图片来源:

1. HttpServlet类处理service

同样的分析,由于service(ServletResquest, ServletResponse)方法其父类HttpServlet已经重写好了,子类没有重写,则调用父类的service()方法。

@Overridepublic void service(ServletRequest req, ServletResponse res)    throws ServletException, IOException{    HttpServletRequest  request;    HttpServletResponse response;        if (!(req instanceof HttpServletRequest &&            res instanceof HttpServletResponse)) {        throw new ServletException("non-HTTP request or response");    }    request = (HttpServletRequest) req;    response = (HttpServletResponse) res;  // 调用子类FrameworkServlet判断请求是否是Patch请求或者null, 如果是的话交给子类处理  // 如果不是返回自己处理    service(request, response);}

2. FrameworkServlet类处理service

@Override	protected void service(HttpServletRequest request, HttpServletResponse response)			throws ServletException, IOException {		HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());		if (httpMethod == HttpMethod.PATCH || httpMethod == null) {			processRequest(request, response);		}		else {      // 返回给HttpServlet类处理			super.service(request, response);		}	}

3 HttpServlet类继续处理service方法

protected void service(HttpServletRequest req, HttpServletResponse resp)    throws ServletException, IOException {     // 获取请求方法名称    String method = req.getMethod();    // 判断请求方法类型,进入到对应的处理分支    // Get请求    if (method.equals(METHOD_GET)) {        long lastModified = getLastModified(req);        if (lastModified == -1) {            // servlet doesn't support if-modified-since, no reason            // to go through further expensive logic            doGet(req, resp);        } else {            long ifModifiedSince;            try {                ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);            } catch (IllegalArgumentException iae) {                // Invalid date header - proceed as if none was set                ifModifiedSince = -1;            }            if (ifModifiedSince < (lastModified / 1000 * 1000)) {                // If the servlet mod time is later, call doGet()                // Round down to the nearest second for a proper compare                // A ifModifiedSince of -1 will always be less                maybeSetLastModified(resp, lastModified);                doGet(req, resp);            } else {                resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);            }        }      // Head请求    } else if (method.equals(METHOD_HEAD)) {        long lastModified = getLastModified(req);        maybeSetLastModified(resp, lastModified);        doHead(req, resp);      // Post    } else if (method.equals(METHOD_POST)) {        doPost(req, resp);      // Put    } else if (method.equals(METHOD_PUT)) {        doPut(req, resp);      // Delete    } else if (method.equals(METHOD_DELETE)) {        doDelete(req, resp);      // Options    } else if (method.equals(METHOD_OPTIONS)) {        doOptions(req,resp);      // Trace    } else if (method.equals(METHOD_TRACE)) {        doTrace(req,resp);    } else {        // 什么请求都不匹配,返回error        String errMsg = lStrings.getString("http.method_not_implemented");        Object[] errArgs = new Object[1];        errArgs[0] = method;        errMsg = MessageFormat.format(errMsg, errArgs);        resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);    }}

4. 以Get请求为例,下面调用doGet请求,由于HttpServlet的子类FrameworkServlet类重写了HttpServlet的doGet方法,因此,将调用FrameworkServlet类的doGet请求。

@Overrideprotected 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 | 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();			}			logResult(request, response, failureCause, asyncManager);			publishRequestHandledEvent(request, response, startTime, failureCause);		}	}

5. 千呼万唤,终于进入到DispatcherServlet类的doService()方法中

在doService方法中,主要是对请求做一些赋值,然后重中之重调用doDispatch方法处理请求。

@Overrideprotected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {   logRequest(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<>();      Enumeration<?> attrNames = request.getAttributeNames();      while (attrNames.hasMoreElements()) {         String attrName = (String) attrNames.nextElement();         if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {            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());   if (this.flashMapManager != null) {      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);   }   RequestPath previousRequestPath = null;   if (this.parseRequestPath) {      previousRequestPath = (RequestPath) request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);      ServletRequestPathUtils.parseAndCache(request);   }   try {     // 终于要处理request啦      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);         }      }      ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);   }}

6. DispatcherServlet的doDispatch处理请求和返回响应

doDispatch处理的大致流程:

通过HandlerMapping获取请求对应的Handler再通过Handler找到对应的HandlerAdapterHandlerAdapterd调用handler方法得到ModelAndView(连接“业务逻辑层”与“视图展示层”的桥梁)通过ModelAndView 获得 View,再通过它的 Model 对 View 进行渲染

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. 判断是否是文件上传请求         processedRequest = checkMultipart(request);         multipartRequestParsed = (processedRequest != request);         // 2. 遍历所有的 HandlerMapping 找到与请求对应的 Handler,并将其与一堆拦截器封装到 HandlerExecutionChain 对象中。         // 返回的HandlerExecutionChain请求处理器链对象封装了handler和interceptors.         mappedHandler = getHandler(processedRequest);         // 如果没有对应的handler,返回404         if (mappedHandler == null) {            noHandlerFound(processedRequest, response);            return;         }         // 3. 获取处理请求的处理器适配器HandlerAdapter         HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());                  // 处理 last-modified 请求头         String method = request.getMethod();         boolean isGet = "GET".equals(method);         if (isGet || "HEAD".equals(method)) {            long lastModified = ha.getLastModified(request, mappedHandler.getHandler());            if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {               return;            }         }         // 请求方法前置拦截,如果返回true 表示会执行到目标方法(请求方法) 如果返回false的情况下,直接return。         if (!mappedHandler.applyPreHandle(processedRequest, response)) {            return;         }                  // 5. 这一步就是调用对应的controller控制器,并返回结果视图对象         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());                  // 如果是异步模式,则返回         if (asyncManager.isConcurrentHandlingStarted()) {            return;         }         // 6. 如果mv不为null,则给其ViewName设置初始默认值         applyDefaultViewName(processedRequest, mv);         // 7. 后置拦截器的postHandle方法的处理         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);      }      // 8. 处理返回结果;(异常处理、页面渲染、拦截器的afterCompletion触发等)      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()) {         //判断是否执行异步请求         if (mappedHandler != null) {            // 如果是的话,就替代拦截器的postHandle 和 afterCompletion方法执行            mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);         }      }      else {         // 删除上传请求的资源         if (multipartRequestParsed) {            cleanupMultipart(processedRequest);         }      }   }}

标签: #net调用servlet接口