源码解析SpringMVC处理请求的完整流程

1.WebMvcAutoConfiguration

在这里插入图片描述
EnableWebMvcConfiguration自动装配类负责加载SpringMVC涉及的HandlerAdapterHandlerMappingExceptionHandlerExceptionResolver等。
SpringMVC利用 DispatchServlet 处理上游Tomcat的请求时,会被HandlerMapping、HandlerAdapter的相关子类分别先后执行,这样做的原因是:

  1. 通过RequestUril找到相应的handler是因为HandlerMapping提前建立了 RequestUril & Handler 之间的映射关系。
  2. 不同HandlerMapping表明解析Handler上的Uri方式是不同的。
  3. HandlerAdapter触发执行 Uri 在Handler中的目标方法。

在这里插入图片描述
WebMvcAutoConfigurationAdapter自动装配类负责加载SpringMVC涉及的静态资源等Web资源。例如LocaleResolver、视图解析器InternalResourceViewResolver、ContentNegotiatingViewResolver等。

@Configuration(proxyBeanMethods = false)
public class WebMvcAutoConfiguration {

	private static final String[] SERVLET_LOCATIONS = { "/" };

	@Configuration(proxyBeanMethods = false)
	@Import(EnableWebMvcConfiguration.class)
	@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
	@Order(0)
	public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
		...
		@Bean
		@ConditionalOnBean(ViewResolver.class)
		@ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
		public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {...}
		...
	}
	// 该注解保证父类WebMvcConfigurationSupport也参与SpringBoot启动过程中各个注解的解析过程
	@Configuration(proxyBeanMethods = false)
	public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
		...
		@Bean
		@Override
		public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
				@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager m,
				@Qualifier("mvcConversionService") FormattingConversionService c,
				@Qualifier("mvcValidator") Validator v) {
			RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(m,c, v);
			boolean ignoreDefaultModelOnRedirect = this.mvcProperties.isIgnoreDefaultModelOnRedirect();
			adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null || ignoreDefaultModelOnRedirect);
			return adapter;
		}
		...
		@Bean
		@Primary
		@Override
		public RequestMappingHandlerMapping requestMappingHandlerMapping(
				@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager manager,
				@Qualifier("mvcConversionService") FormattingConversionService conversionService,
				@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
			// 调用父类WebMvcConfigurationSupport
			return super.requestMappingHandlerMapping(manager, conversionService,resourceUrlProvider);
		}
		...
	}
}

1.2.WebMvcConfigurationSupport

public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
	@Bean
	public RequestMappingHandlerMapping requestMappingHandlerMapping(...}
	
	@Bean
	public PathMatcher mvcPathMatcher() {...}
	
	@Bean
	public BeanNameUrlHandlerMapping beanNameHandlerMapping(...}
	
	@Bean
	public HandlerExceptionResolver handlerExceptionResolver(
			@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {
		List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<>();
		configureHandlerExceptionResolvers(exceptionResolvers);
		if (exceptionResolvers.isEmpty()) {
			addDefaultHandlerExceptionResolvers(exceptionResolvers, contentNegotiationManager);
		}
		extendHandlerExceptionResolvers(exceptionResolvers);
		HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
		composite.setOrder(0);
		composite.setExceptionResolvers(exceptionResolvers);
		return composite;
	}
}

1.2.1.生成HandlerMapping

默认生成的众多HandlerMapping子类中,核心包括RequestMappingHandlerMappingBeanNameUrlHandlerMappingSimpleUrlHandlerMapping

HandlerMapping其核心功能是建立RequestUri与目标handler之间的映射关系。
在这里插入图片描述
RequestMappingHandlerMapping解析的handler其Uri是被注解@RequestMapping标识的。
BeanNameUrlHandlerMapping解析的Handler其Uri就是该Handler在IOC容器中bean实例对应的beanName。
SimpleUrlHandlerMapping解析的handler其Uri是显式指定的。如下所示:

public SimpleUrlHandlerMapping simpleUrlHandlerMapping(){
    SimpleUrlHandlerMapping simpleUrlHandlerMapping = new SimpleUrlHandlerMapping();
    Properties properties = new Properties();
//      suHm:访问uri,suHmBean:对应的控制器bean
    properties.setProperty("suHm","suHmBean");
    simpleUrlHandlerMapping.setMappings(properties);
    simpleUrlHandlerMapping.setOrder(1);
    return simpleUrlHandlerMapping;
}

BeanNameUrlHandlerMapping & SimpleUrlHandlerMapping的异同:

  1. 相同点:两者解析的handler存在的共同点其中一点是都必须实现Controller接口,另外一点是每一个handler跟Uri是一一对应关系。
  2. 不同点:BeanNameUrlHandlerMapping对应的Uri没得选,只能是该handler在IOC容器中bean实例对应的beanName。SimpleUrlHandlerMapping对应的handler其具体的Uri,如上所示,是可以被任意指定的。

1.2.2.生成HandlerAdapter

类HandlerAdapter负责触发目标类目标方法的执行。

BeanNameUrlHandlerMapping & SimpleUrlHandlerMapping对应的HandlerAdapter为SimpleControllerHandlerAdapter。

RequestMappingHandlerAdapter、SimpleControllerHandlerAdapter是常见的HandlerAdapter,其中SimpleControllerHandlerAdapter负责处理实现接口Controller的handler。
在这里插入图片描述

1.2.3.生成HandlerExceptionResolver

具体参考文章

2.DispatcherServlet

public class DispatcherServlet extends FrameworkServlet {
	protected void doDispatch(HttpServletRequest request, HttpServletResponse response){
		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);
				...
				// Determine handler adapter for the current request.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
				// Process last-modified header, if supported by the handler.
				...
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}
				// Actually invoke the handler. 
				// 执行目标类的目标方法,即有可能返回ModelAndView,也可能只有HttpServletResponse。其实ModelAndView是执行完目标方法	
				//进一步渲染视图,渲染后的视图最终还是通过HttpServletResponse响应到客户端。如果没有视图则ModelAndView为null,最终目标
				//方法的返回值被对应handler写到HttpServletResponse并响应到客户端。
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
				// 如果存在ModelAndView 则渲染视图,否则直接忽略
				applyDefaultViewName(processedRequest, mv);
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}...
			//渲染目标方法返回结果
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			mappedHandler.triggerAfterCompletion(request, response, ex);
		}
		...
	}
	
	private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
							HandlerExecutionChain mappedHandler,ModelAndView mv,Exception exception) {
		boolean errorView = false;
		if (mv != null && !mv.wasCleared()) {
			// 这种情况主要是对视图View的渲染
			render(mv, request, response);
			...
		}
		if (mappedHandler != null) {
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}
}

对于SimpleControllerHandlerAdapter,其目标方法即为接口Controller的抽象方法,在子类重写其方法内部最终返回值为ModelAndView类型以及HttpServletResponse。如果最终结果存在视图渲染则ModelAndView类型是视图相关内容,最终将HttpServletResponse内部响应结果渲染至ModelAndView代表的视图中。

2.1.Servlet维护SpringMVC九大组件

public class DispatcherServlet extends FrameworkServlet {

	private List<HandlerMapping> handlerMappings;
	private List<HandlerExceptionResolver> handlerExceptionResolvers;
	private List<HandlerAdapter> handlerAdapters;
	
	@Override//Tomcat处理请求过程中触发
	protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}
	
	protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		//handlerMappings中添加所有元素:从IOC容器中获取HandlerMapping接口的全部相关子类。
		initHandlerMappings(context);
		//HandleAdapter中添加所有元素:从IOC容器中获取HandleAdapter接口的全部相关子类。
		initHandlerAdapters(context);
		//同理...
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}
}

Servlet容器之Tomcat处理请求过程中触发 初始化SpringMVC九大组件 的流程。此时DispatcherServlet类中集合类型的属性之handlerMappings & handlerExceptionResolvers & handlerAdapters中元素均为SpringBoot自动装配类组件,截止当前所有组件已经初始化完毕,只需从IOC容器获取相关类型的组件即可。目的是用于处理客户端请求,由此得知该集合类型赋值过程有且仅有一次,即处理首次客户端请求。

2.2.执行HandlerMapping

着重关注三种类型之RequestMappingHandlerMappingBeanNameUrlHandlerMappingSimpleUrlHandlerMapping的执行流程。

public class DispatcherServlet extends FrameworkServlet {
	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;
	}
}
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping{
	
	public final HandlerExecutionChain getHandler(HttpServletRequest request) {
		// 通过requestUri获取对应的handler
		Object handler = getHandlerInternal(request);
		...
		HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
		...
		return executionChain;
	}
}

其中,RequestMappingHandlerMapping得到的handler类型为HandlerMethod【对目标方法的抽象化】,在HandlerMethod内部维护元素:目标handler的真实类型 以及 目标方法Method

2.2.1.RequestMappingHandlerMapping

public class RequestMappingHandlerMapping{
	@Override
	protected HandlerMethod getHandlerInternal(HttpServletRequest request){
		// AbstractHandlerMethodMapping#getHandlerInternal
		return super.getHandlerInternal(request);
	}
}
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping {
	@Override
	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
		return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
	}
}

2.2.1.BeanNameUrlHandlerMapping & SimpleUrlHandlerMapping

BeanNameUrlHandlerMapping & SimpleUrlHandlerMapping 该俩HandlerMapping通过requestUri获取得到的handler为接口Controller类型的没有做任何抽象的实际handler。

2.3.执行HandlerAdapter

RequestMappingHandlerAdapter、SimpleControllerHandlerAdapter是常见的HandlerAdapter。

通过如下方法返回符合当前请求的HandlerAdapter。

public class DispatcherServlet extends FrameworkServlet {

	protected HandlerAdapter getHandlerAdapter(Object handler)  {
		if (this.handlerAdapters != null) {
			for (HandlerAdapter adapter : this.handlerAdapters) {
				if (adapter.supports(handler)) {
					return adapter;
				}
			}
		}
	}
}

2.3.1.RequestMappingHandlerAdapter

由其抽象类AbstractHandlerMethodAdapter完成目标HandlerAdapter的鉴定条件。

public abstract class AbstractHandlerMethodAdapter{
	@Override
	public final boolean supports(Object handler) {
		return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
	}
}

2.3.2.SimpleControllerHandlerAdapter

符合处理BeanNameUrlHandlerMapping & SimpleUrlHandlerMapping的HandlerAdapter两种类型的HandlerAdapter即为当前的SimpleControllerHandlerAdapter。因为两者HandlerMapping对应目标handler都是直接实现Controller接口。

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

	@Override
	public boolean supports(Object handler) {
		return (handler instanceof Controller);
	}
}

3.执行handler目标方法

着重分析RequestMappingHandlerAdapter以及SimpleControllerHandlerAdapter。

3.1.RequestMappingHandlerAdapter

public abstract class AbstractHandlerMethodAdapter{
	@Override
	@Nullable
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		return handleInternal(request, response, (HandlerMethod) handler);
	}
}
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
		implements BeanFactoryAware, InitializingBean {
		
	@Override
	protected ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod){
			...
		return invokeHandlerMethod(request, response, handlerMethod);;
	}
	
	@Nullable
	protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
			...
			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
			//设置目标方法所有参数的抽象体
			invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
			//设置目标方法返回值的抽象体
			invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
			...
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
	}
}

3.1.1.ServletInvocableHandlerMethod

public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {

	private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
	
	public void invokeAndHandle(ServletWebRequest wr,ModelAndViewContainer mc,Object... args){
		// 调用目标方法得到的实际返回值
		Object returnValue = invokeForRequest(webRequest, mc, args);
		if(returnValue == null)return;
		MethodParameter mp = getReturnValueType(returnValue);
		// 处理返回值
		this.returnValueHandlers.handleReturnValue(returnValue, mp, mc, wr);
	}
}

3.2.SimpleControllerHandlerAdapter

BeanNameUrlHandlerMapping & SimpleUrlHandlerMapping 两者对应的实际handler都是直接实现接口Controller。所以对于上述两种HandlerMapping,当前HandlerAdapter执行两者目标类的目标方法其实都是重写接口Controller的方法handleRequest。

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

	@Override
	public boolean supports(Object handler) {
		return (handler instanceof Controller);
	}

	@Override
	@Nullable
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// 直接调用目标类的目标方法
		return ((Controller) handler).handleRequest(request, response);
	}
}

4.响应内容之HandlerMethodReturnValueHandlerComposite

本章节不分析SpringMVC渲染视图等结果行为,只分析RequestMappingHandlerMapping对应的响应结果。

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
		implements BeanFactoryAware, InitializingBean {

	@Override
	public void afterPropertiesSet() {
		// 注意与全部异常拦截的区别
		initControllerAdviceCache();
		...
		if (this.returnValueHandlers == null) {
			List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
			// 一共提供了15种类型
			this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
		}
	}
}
public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {
	//returnValueHandlers元素:支持返回值类型为15种
	private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>();
	
	public HandlerMethodReturnValueHandlerComposite addHandlers(
			List<? extends HandlerMethodReturnValueHandler> handlers) {
	
		if (handlers != null) {
			this.returnValueHandlers.addAll(handlers);
		}
		return this;
	}
	
	@Override
	public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
		//将 handler实际返回值returnValue 包装为 ReturnValueMethodParameter类型
		HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
		handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
	}
	
	@Nullable
	private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {
		for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
			// 本文着重分析handler之RequestResponseBodyMethodProcessor
			if (handler.supportsReturnType(returnType)) {
				return handler;
			}
		}
		return null;
	}
}

15种返回值类型解析handler,如下所示:
在这里插入图片描述

4.1.RequestResponseBodyMethodProcessor

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
	@Override
	public boolean supportsReturnType(MethodParameter returnType) {
		//目标类注解中是否存在ResponseBody注解
		return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
				// 目标方法是否存在ResponseBody注解
				returnType.hasMethodAnnotation(ResponseBody.class));
	}
	
	@Override
	public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
	
		mavContainer.setRequestHandled(true);
		ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
		ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
		// 最后通过响应头的响应类型返回,否则根据目标方法实际返回值类型返回
		// Try even with null return value. ResponseBodyAdvice could get involved.
		writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值