springmvc源码分析3-DispatcherServlet

  1.springmvc中DispatcherServlet继承体系

2.概述

1)初始化各种组件

主要组件有

  1. MultipartResolver:文件上传处理
  2. LocaleResolver:多语言支持
  3. ThemeResolver:切换主题
  4. HandlerMappings:处理器,这个请求的处理器
  5. HandlerAdapters:处理器适配器,调用处理器
  6. HandlerExceptionResolvers:全局异常处理
  7. RequestToViewNameTranslator:如果没有指定的视图,会将http请求转为视图
  8. ViewResolvers:视图解析,逻辑上的视图名称解析为一个真正的视图
  9. FlashMapManager:重定向管理

 2)http中央调度处理程序,实际请求分发到JavaBean,通常转发到controller中@RequestMapping路径的方法,也可以是实现controller接口的方法等

3.DispatcherServlet整个代码用工具翻译后的

springmvc源码-DispatcherServlet_LouD_dm的博客-CSDN博客_springmvc 源码

4.初始化各种组件

1)首先在DispatcherServlet实现了FrameworkServlet的onRefresh方法,在onRefresh方法初始化各种组件

	/**
	 * 这个实现调用{@link#initStrategies}。
	 */
	@Override
	protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}

	/**
	 * 初始化此servlet使用的策略对象。
	 * <p>可以在子类中重写,以初始化其他策略对象。
	 */
	protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}

2)detectAllHandlerMappings默认为true,会检测spring容器中所有HandlerMapping类型的bean,如果为空,获取配置文件下的默认策略

/**
	 * 初始化此类使用的HandlerMappings。
	 * *<p>如果BeanFactory中没有为此命名空间定义HandlerMapping bean,
	 * *我们默认为BeanNameUrlHandlerMapping。
	 */
	private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;

		if (this.detectAllHandlerMappings) {
			// 在ApplicationContext中查找所有HandlerMappings,包括祖先上下文。
			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerMappings = new ArrayList<>(matchingBeans.values());
				//我们保持handler映射的有序性。
				AnnotationAwareOrderComparator.sort(this.handlerMappings);
			}
		} else {
			try {
				HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
				this.handlerMappings = Collections.singletonList(hm);
			} catch (NoSuchBeanDefinitionException ex) {
				//忽略,我们稍后将添加默认HandlerMapping。
			}
		}

		// 通过注册,确保我们至少有一个HandlerMapping
		// 如果找不到其他映射,则为默认HandlerMapping。
		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中有一个static块,加载对应的DispatcherServlet.properties的默认策略

	private static final Properties defaultStrategies;

	static {
		//从属性文件加载默认策略实现。
        //这是目前严格的内部,并不意味着定制
        //应用程序开发人员。
		try {
			ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
			defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
		} catch (IOException ex) {
			throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
		}
	}

DispatcherServlet.properties文件内容

# DispatcherServlet 的策略接口的默认实现类。
# 当在 DispatcherServlet 上下文中找不到匹配的 bean 时用作回退。
# 不打算由应用程序开发人员定制。

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
	org.springframework.web.servlet.function.support.RouterFunctionMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
	org.springframework.web.servlet.function.support.HandlerFunctionAdapter


org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

getDefaultStrategies方法从配置文件中获取默认的策略,反射实例化并返回

/**
	 *为给定的策略接口创建默认策略对象列表。
	 * * <p>默认实现使用“DispatcherServlet”。属性”文件(在相同的
	 * *包为DispatcherServlet类)来确定类名。它实例化
	 * *策略通过上下文的BeanFactory对象。
	 *
	 * @param context           the current WebApplicationContext
	 * @param strategyInterface the strategy interface
	 * @return the List of corresponding strategy objects
	 */
	@SuppressWarnings("unchecked")
	protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
		String key = strategyInterface.getName();
		String value = defaultStrategies.getProperty(key);
		if (value != null) {
			String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
			List<T> strategies = new ArrayList<>(classNames.length);
			for (String className : classNames) {
				try {
					Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
					Object strategy = createDefaultStrategy(context, clazz);
					strategies.add((T) strategy);
				} catch (ClassNotFoundException ex) {
					throw new BeanInitializationException(
							"Could not find DispatcherServlet's default strategy class [" + className +
									"] for interface [" + key + "]", ex);
				} catch (LinkageError err) {
					throw new BeanInitializationException(
							"Unresolvable class definition for DispatcherServlet's default strategy class [" +
									className + "] for interface [" + key + "]", err);
				}
			}
			return strategies;
		} else {
			return new LinkedList<>();
		}
	}

5.请求实际分发

1)DispatcherServlet实现了FrameworkServlet的doService的方法

@Override
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		logRequest(request);

		// 如果包含,请保留请求属性的快照,
		//以便能够在包含之后恢复原始属性。
		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));
				}
			}
		}

		// 使框架对象可用于处理程序并查看对象。
		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
			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()) {
				//如果包含,则还原原始属性快照.
				if (attributesSnapshot != null) {
					restoreAttributesAfterInclude(request, attributesSnapshot);
				}
			}
		}
	}

主要是doDispatch方法,实际分发请求

/**
	 * 处理向处理程序的实际分派。
	 * <p>该处理程序将通过依次应用servlet的HandlerMappings获得。
	 * HandlerAdapter将通过查询Servlet的已安装HandlerAdapters获得。
	 * 查找第一个支持处理程序类的对象。
	 * <p>所有HTTP方法均由该方法处理。由HandlerAdapters或处理程序决定
	 * 自己决定可接受的方法。
	 *
	 * @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 asyncManager = WebAsyncUtils.getAsyncManager(request);

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

			try {
				//校验是否是文件上传请求
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// 确定当前请求的处理程序。并封装为一个HandlerExecutionChain类
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == 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());
					//浏览器缓存,校验如果资源在lastModified时间内没有更改,并且是get或head请求,直接返回
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}
				//调用拦截器处理前的方法
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// 实际调用处理程序。
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
				//视图名称转换
				applyDefaultViewName(processedRequest, mv);
				//调用拦截器处理后的方法
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			} catch (Exception ex) {
				dispatchException = ex;
			} catch (Throwable err) {
				// 从4.3开始,我们也在处理处理程序方法抛出的错误,
				使它们可用于@ExceptionHandler方法和其他场景。
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
			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) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			} else {
				// 清理多部分请求使用的所有资源。
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

1.doDispatch方法中获取异步管理类WebAsyncManager,在finally中校验如果是异步请求执行异步处理

2.校验是否是文件上传请求,如果是将给定的HTTP请求解析为多部分文件和参数,并且将请求转换为MultipartHttpServletRequest

/**
	 * 将请求转换为多部分请求,并使多部分解析器可用。
	 * <p>如果未设置多部分解析器,则只需使用现有请求。
	 *
	 * @param request current HTTP request
	 * @return the processed request (multipart wrapper if necessary)
	 * @see MultipartResolver#resolveMultipart
	 */
	protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
		if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
			if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
				if (request.getDispatcherType().equals(DispatcherType.REQUEST)) {
					logger.trace("Request already resolved to MultipartHttpServletRequest, e.g. by MultipartFilter");
				}
			} else if (hasMultipartException(request)) {
				logger.debug("Multipart resolution previously failed for current request - " +
						"skipping re-resolution for undisturbed error rendering");
			} else {
				try {
					return this.multipartResolver.resolveMultipart(request);
				} catch (MultipartException ex) {
					if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) {
						logger.debug("Multipart resolution failed for error dispatch", ex);
						// 使用下面的常规请求句柄保持处理错误的分派
					} else {
						throw ex;
					}
				}
			}
		}
		// 如果之前未返回:返回原始请求。
		return request;
	}

3.遍历当前的所有处理器,根据当前请求获取,获取到和拦截器封装为一个HandlerExecutionChain并返回,否则返回为空,在外边如果没有对应的处理器返回错误的信息

如果没有配置,在前面DispatcherServlet.properties中默认配置有BeanNameUrlHandlerMapping,RequestMappingHandlerMapping和RouterFunctionMapping

BeanNameUrlHandlerMapping初始化和getHandler方法处理逻辑

1)AbstractHandlerMapping

springmvc组件HandleMapping源码分析-AbstractHandlerMapping_LouD_dm的博客-CSDN博客

2)AbstractUrlHandlerMapping

springmvc组件HandleMapping源码分析-AbstractUrlHandlerMapping_LouD_dm的博客-CSDN博客

3)AbstractDetectingUrlHandlerMapping

springmvc组件HandleMapping源码分析-AbstractDetectingUrlHandlerMapping_LouD_dm的博客-CSDN博客

4)BeanNameUrlHandlerMapping

springmvc组件HandleMapping源码分析-BeanNameUrlHandlerMapping_LouD_dm的博客-CSDN博客

RequestMappingHandlerMapping初始化和getHandler方法处理逻辑

1)AbstractHandlerMapping

springmvc组件HandleMapping源码分析-AbstractHandlerMapping_LouD_dm的博客-CSDN博客

2)AbstractHandlerMethodMapping

springmvc组件HandleMapping源码分析-AbstractHandlerMethodMapping_LouD_dm的博客-CSDN博客

3)RequestMappingHandlerMapping

springmvc组件HandleMapping源码分析-RequestMappingHandlerMapping_LouD_dm的博客-CSDN博客

	/**
	 * 返回此请求的HandlerExecutionChain。
	 * <p>按顺序尝试所有处理程序映射.
	 *
	 * @param request current HTTP request
	 * @return the HandlerExecutionChain, or {@code null} if no handler could be found
	 */
	@Nullable
	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			for (HandlerMapping mapping : this.handlerMappings) {
				HandlerExecutionChain handler = mapping.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

4.根据处理器获取处理器适配器,也就是这个处理器对应的执行者

RequestMappingHandlerAdapter处理HandleMethed类型的处理器

1.AbstractHandlerMethodAdapter

springmvc组件HandlerAdapter源码分析-AbstractHandlerMethodAdapter_LouD_dm的博客-CSDN博客

2.RequestMappingHandlerAdapter

springmvc组件HandlerAdapter源码分析-RequestMappingHandlerAdapter_LouD_dm的博客-CSDN博客

/**
	 * 返回此处理程序对象的HandlerAdapter。
	 *
	 * @param handler 处理程序对象以查找适配器
	 * @throws ServletException 如果找不到处理程序的HandlerAdapter。这是一个致命错误。
	 */
	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters != null) {
			for (HandlerAdapter adapter : this.handlerAdapters) {
				if (adapter.supports(handler)) {
					return adapter;
				}
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}

5.浏览器请求缓存

6.在处理程序之前,调用拦截器的前置方法

springmvc拦截器源码分析-HandlerInterceptor接口_LouD_dm的博客-CSDN博客

	/**
	 * 应用注册拦截器的preHandle方法。
	 *
	 * @return {@code true} if the execution chain should proceed with the
	 * next interceptor or the handler itself. Else, DispatcherServlet assumes
	 * that this interceptor has already dealt with the response itself.
	 */
	boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
		//获取所有的拦截器
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = 0; i < interceptors.length; i++) {
				HandlerInterceptor interceptor = interceptors[i];
				//调用前置处理方法
				if (!interceptor.preHandle(request, response, this.handler)) {
					triggerAfterCompletion(request, response, null);
					return false;
				}
				this.interceptorIndex = i;
			}
		}
		return true;
	}

7.使用处理器适配器处理,并返回ModelAndView

 RequestMappingHandlerAdapter处理HandleMethed类型的处理器

1.AbstractHandlerMethodAdapter

springmvc组件HandlerAdapter源码分析-AbstractHandlerMethodAdapter_LouD_dm的博客-CSDN博客

2.RequestMappingHandlerAdapter

springmvc组件HandlerAdapter源码分析-RequestMappingHandlerAdapter_LouD_dm的博客-CSDN博客

8.视图名称转换

	/**
	 * 我们需要视图名称转换吗?
	 */
	private void applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) throws Exception {
		if (mv != null && !mv.hasView()) {
			String defaultViewName = getDefaultViewName(request);
			if (defaultViewName != null) {
				mv.setViewName(defaultViewName);
			}
		}
	}

9.在处理之后,调用拦截器的后置方法

	/**
	 * 应用注册拦截器后的方法。
	 */
	void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
			throws Exception {
		//获取当前所有的拦截器
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = interceptors.length - 1; i >= 0; i--) {
				HandlerInterceptor interceptor = interceptors[i];
				//调用后置处理方法
				interceptor.postHandle(request, response, this.handler, mv);
			}
		}
	}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LouD_dm

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值