SpringMVC中servlet处理http请求源码解析

    Spring MVC的核心控制器为Servlet,所有访问服务端的请求都将由servlet拦截接受,并进行相应处理最终进行返回。下面我们来看看它究竟是怎么做的。

    SpringMVC中的Servlet一共有三个层次,分别是HttpServletBean、FrameworkServlet和 DispatcherServlet。

      HttpServletBean直接继承自java的HttpServlet,其作用是将Servlet中配置的参数设置到相应的属性;FrameworkServlet初始化WebApplicationContext,而DispatchServlet初始化SpringMVC九大组件。可以具体看代码:

    // 初始化servlet九大组件
    protected void initStrategies(ApplicationContext context) {
		// 初始化文件上传组件,将普通的request包装成MultipartHttpServletRequest,后者可以直接通过getFile获取文件
		initMultipartResolver(context);
		// 初始化local解析器(EN-US;ZH-CN)
		initLocaleResolver(context);
		// 初始化主题解析器
		initThemeResolver(context);
		// 初始化HandlerMapping
		initHandlerMappings(context);
		// 初始化HandlerAdapters
		initHandlerAdapters(context);
		// 初始化全局异常处理类
		initHandlerExceptionResolvers(context);
		// 初始化RequestToViewNameTranslator,从request中获取ViewName
		initRequestToViewNameTranslator(context);
		// 初始化视图解析器,将String类型视图名和local解析为View类型视图
		initViewResolvers(context);
		// 初始化FlashMap(FlashMap用于在redirect中传递参数)
		initFlashMapManager(context);
	}

而http请求被servlet拦截后都将调用doService方法以调度到具体的handlerMapping中进行处理:

/**
	 * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
	 * for the actual dispatching.
	 */
	@Override
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		if (logger.isDebugEnabled()) {
			// 获取请求来源uri
			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.
		// 将request请求中的各个属性参数放入一个快照Map中
		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();
				// cleanupAfterInclude默认为true,若为servlet参数则放入Map中
				if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
					attributesSnapshot.put(attrName, request.getAttribute(attrName));
				}
			}
		}

		// Make framework objects available to handlers and view objects.
		// 将mvc的webApplicationContext、主题解析器、主题、local解析器放入请求参数中
		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,然后删除过期的FlashMap,并选取一个适合当前请求的FlashMap返回
		FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
		// 若找到合适的FlashMap,将其转换成一个不可变Map(不支持任何修改操作 put,remove,clear都将报错),放入请求参数中
		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 {
			// 将请求调度至handlerMapping处理
			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);
			}
		}
	}

dodispatch方法将真正将请求定位至处理方法中,并在其中加入拦截器的处理、异常处理、返回视图的构建:

	/**
	 * Process the actual dispatching to the handler.
	 * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
	 * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
	 * to find the first that supports the handler class.
	 * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
	 * themselves to decide which methods are acceptable.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @throws Exception in case of any kind of processing failure
	 */
	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;
		//WebAsyncManager主要用来管理异步请求的处理,当业务逻辑复杂(或者其他原因),为了避免请求线程阻塞,需要委托给另一个线程时使用
		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
				// 判断请求是否为文件上传类型,若是则返回MultipartRequest,若否则返回原request	
				processedRequest = checkMultipart(request);
				// 判断是否为MultipartRequest标识,若上一句 返回不是原request则证明是MultipartRequest
				multipartRequestParsed = processedRequest != request;

				// Determine handler for the current request.
				// handlerMappings中包含了所有注册在IOC容器中的Handler
				// ①遍历handlerMappings列表,找到与request中请求名称相同的handler,通过ApplicationContext.getBean方法获取handlerBean
				// ②通过获取到的handlerBean再获取可将handler拦截的拦截器链
				mappedHandler = getHandler(processedRequest);
				// 若未找到对应的handler则抛出异常或返回http-404
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				// 通过handler找到对应的HandlerAdapter
				// HandlerAdapter为处理器适配器,作用为根据请求去定位请求的具体处理方法是哪个
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				// 若此http请求为get方法,则获取浏览器端上送的最后修改时间,若最后修改时间与服务器端一致,则说明无变化
				// 无变化则方法直接返回,浏览器可继续用上次get方法获取到的数据缓存即可
				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;
					}
				}
				// 此处依次遍历执行拦截器链的preHandler方法,若其中有一个return false或者抛出异常则执行拦截器链的afterCompletion方法,最后return此次请求
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}
				// 通过handlerAdapter定位到具体的处理方法处理请求
				try {
					// Actually invoke the handler.
					mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
				}
				finally {
					if (asyncManager.isConcurrentHandlingStarted()) {
						return;
					}
				}
				// 获取ModelAndView
				applyDefaultViewName(request, mv);
				// 此处反序遍历执行拦截器链的postHandler方法
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			// 处理请求的返回信息:若有异常则返回异常视图;若返回正常则调用render方法返回正常视图
			// 并反序执行拦截器链的afterCompletion方法
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			// 若抛出异常也需反序执行拦截器链的afterCompletion方法
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Error err) {
			// 若抛出Error级异常也需反序执行拦截器链的afterCompletion方法
			triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				return;
			}
			// Clean up any resources used by a multipart request.
			// 若为文件上传请求,最后还需清理掉上传文件的缓存信息
			if (multipartRequestParsed) {
				cleanupMultipart(processedRequest);
			}
		}
	}


猜你喜欢

转载自blog.csdn.net/smartValentines/article/details/79954810