DispatcherServlet解析

版权声明: https://blog.csdn.net/ph3636/article/details/79494009
1.DispatcherServlet主要的外层方法主要有initStrategies初始化各种资源策略,再就是doService主要的请求处理方法
protected void initStrategies(ApplicationContext context) {  
        initMultipartResolver(context);  
        initLocaleResolver(context);  
        initThemeResolver(context);  
        initHandlerMappings(context);  
        initHandlerAdapters(context);  
        initHandlerExceptionResolvers(context);  
        initRequestToViewNameTranslator(context);  
        initViewResolvers(context);  
        initFlashMapManager(context);  
    }  

2.默认设置的配置文件DispatcherServlet.properties,保存在属性Properties defaultStrategies中

# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.

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.annotation.DefaultAnnotationHandlerMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
	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

3.initMultipartResolver初始化文件上传解析器,在SpringMVC上传文件时,Controller对应方法的参数必须是MultipartFile file,且要进行CommonsMultipartResolver的相关配置,这样在参数解析的时候才会对文件类型进行匹配的解析

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="UTF-8"/>
        <property name="maxUploadSize" value="15728640"/>
    </bean>
3.initLocaleResolver本地化解析,没有显式设置的话,就从defaultStrategies获取默认值AcceptHeaderLocaleResolver
private void initLocaleResolver(ApplicationContext context) {
		try {
			this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
			if (logger.isDebugEnabled()) {
				logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
			}
		}
		catch (NoSuchBeanDefinitionException ex) {
			// We need to use the default.
			this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
			if (logger.isDebugEnabled()) {
				logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +
						"': using default [" + this.localeResolver + "]");
			}
		}
	}

获取默认配置,使用反射获取Class文件,然后在容器中创建bean后返回。

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<T>(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(
							"Error loading DispatcherServlet's default strategy class [" + className +
									"] for interface [" + key + "]: problem with class file or dependent class", err);
				}
			}
			return strategies;
		}
		else {
			return new LinkedList<T>();
		}
	}

4.initThemeResolver主题设置,同样设置默认值FixedThemeResolver

5.initHandlerMappings请求路径映射方法的处理器配置,系统默认会有四个相关配置类RequestMappingHandlerMapping, SimpleUrlHandlerMapping,BeanNameUrlHandlerMapping,SimpleUrlHandlerMapping,可以实现不同的路径方法映射方式

6.initHandlerAdapters初始化处理器适配设置,RequestMappingHandlerAdapter,HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter

7.initHandlerExceptionResolvers初始化异常处理器,ExceptionHandlerExceptionResolver,ResponseStatusExceptionResolver,DefaultHandlerExceptionResolver,WebErrorExceptionResolver,因为我们要防止后台的错误信息展示在前端页面,并且在异常出现时可以给前端展示一些友好的信息,所以我们一般情况下都会设置自己项目的异常处理器WebErrorExceptionResolver,通过继承AbstractHandlerExceptionResolver,然后实现的doResolveException方法,最后通过下面的配置文件显式设置bean,或者直接使用注解都可以@Component,当然要确保组件扫描的路径中包含该类

 <bean class="com.ph3636.WebErrorExceptionResolver"/>

8.initRequestToViewNameTranslator,默认设置为DefaultRequestToViewNameTranslator

9.initViewResolvers初始化视图设置,默认是InternalResourceViewResolver,设置获取数据后的渲染视图,如果希望前端使用jsp进行开发的话,就需要对InternalResourceViewResolver的部分属性进行配置,前后端分离并且通讯数据格式为json的话就不需要配置,默认就可以

10.initFlashMapManager,默认是SessionFlashMapManager

11.DispatcherServlet接收客户端请求开始进行处理,给request设置属性,后续会用到这些

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 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);
			}
		}
	}

12.进入处理方法doDispatch

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;

				// Determine handler for the current request.
				mappedHandler = getHandler(processedRequest);
				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()) {
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				try {
					// Actually invoke the handler.
					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()) {
				// Instead of postHandle and afterCompletion
				mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				return;
			}
			// Clean up any resources used by a multipart request.
			if (multipartRequestParsed) {
				cleanupMultipart(processedRequest);
			}
		}
	}

判断该请求是不是上传文件的请求,通过contentType是不是"multipart/"开头并且是POST方法

processedRequest = checkMultipart(request);

如果是上传文件,multipartResolver.resolveMultipart(request);解析请求,设置文件编码,判断文件大小是否超过限制,把文件包装成springmvc需要的文件类,最后设置标识位multipartRequestParsed

MultipartParsingResult parsingResult = parseRequest(request);
			return new DefaultMultipartHttpServletRequest(request, parsingResult.getMultipartFiles(),
					parsingResult.getMultipartParameters(), parsingResult.getMultipartParameterContentTypes());

13.获取请求处理器执行链HandlerExecutionChain mappedHandler = getHandler(processedRequest);,RequestMappingHandlerMapping首先根据请求路径获取对应Controller的方法HandlerMethod,这些数据在组件扫描的时候已经设置过了,获取对应路径的拦截器,当一个HandlerMapping处理成功后,也就是返回的处理器执行链不为空,后续的HandlerMapping直接略过。然后返回。当没有找到对应的处理器执行链,或者执行方法不存在时,给前端返回404错误noHandlerFound(processedRequest, response);response.sendError(HttpServletResponse.SC_NOT_FOUND);

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
		HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
				(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
		chain.addInterceptors(getAdaptedInterceptors());

		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
		for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) {
			if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
				chain.addInterceptor(mappedInterceptor.getInterceptor());
			}
		}

		return chain;
	}

14.HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());获取对应请求的HandlerAdapter,

15.开始执行拦截器前置处理mappedHandler.applyPreHandle(processedRequest, response),也就是执行preHandle方法,如果执行失败就会执行afterCompletion,然后结束流程

16.执行方法处理器mv = ha.handle(processedRequest, response, mappedHandler.getHandler());方法入参解析,模型视图匹配,方法出参解析。

17.自适应默认view,applyDefaultViewName(request, mv);执行拦截器后置处理mappedHandler.applyPostHandle(processedRequest, response, mv);,拦截器的postHandle方法

18.处理结果信息processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);,当执行结果出现异常时,获取设置过得异常处理器,执行resolveException方法,

for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
			exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
			if (exMv != null) {
				break;
			}
		}
正常结果最后通过视图展示出来,render(mv, request, response);-》view.render(mv.getModelInternal(), request, response);清理遗留资源,结束执行。


猜你喜欢

转载自blog.csdn.net/ph3636/article/details/79494009
今日推荐