首页 > 编程语言 >SpringMVC源码-创建RequestMappingHandlerAdapter

SpringMVC源码-创建RequestMappingHandlerAdapter

时间:2022-11-03 21:01:24浏览次数:37  
标签:resolvers handlers SpringMVC List add 源码 RequestMappingHandlerAdapter new

一、RequestMappingHandlerAdapter

RequestMappingHandlerAdapter所属BeanDifinition的属性。

RequestMappingHandlerAdapter是将当前请求适配到@RequestMapping类型的Handler处理器。handler指的是Spring处理具体请求的某个Controller的方法。

HandlerAdapter

public interface HandlerAdapter {

/**
是否支持handle
 */
boolean supports(Object handler);

/**
 使用handle处理request
 */
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

/**
 * 与HttpServlet的getLastModified方法相同
 */
long getLastModified(HttpServletRequest request, Object handler);

}

HandlerAdapter指的是将当前请求适配到某个Handler的处理器。

HandlerAdapter的实现:

RequestMappingHandlerAdapter:将当前请求适配到@RequestMapping类型的Handler处理器。
HttpRequestHandlerAdapter:适配使用通用DispatcherServlet的HttpRequestHandler接口。
SimpleControllerHandlerAdapter:适配使用通用DispatcherServlet的Controller工作流接口。

二、实例化RequestMappingHandlerAdapter

RequestMappingHandlerAdapter

public RequestMappingHandlerAdapter() {
	this.messageConverters = new ArrayList<>(4);
	this.messageConverters.add(new ByteArrayHttpMessageConverter());
	this.messageConverters.add(new StringHttpMessageConverter());
	if (!shouldIgnoreXml) {
		try {
			this.messageConverters.add(new SourceHttpMessageConverter<>());
		}
		catch (Error err) {
			// Ignore when no TransformerFactory implementation is available
		}
	}
	this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
}

初始化messageConverters集合,并添加ByteArrayHttpMessageConverter,StringHttpMessageConverter和AllEncompassingFormHttpMessageConverter。如果shouldIgnoreXml为false则添加SourceHttpMessageConverter。

RequestMappingHandlerAdapter.afterPropertiesSet()

	public void afterPropertiesSet() {
	// Do this first, it may add ResponseBody advice beans
	initControllerAdviceCache();

	if (this.argumentResolvers == null) {
		List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
		this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
	}
	if (this.initBinderArgumentResolvers == null) {
		List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
		this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
	}
	if (this.returnValueHandlers == null) {
		List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
		this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
	}
}

1、调用initControllerAdviceCache设置@ModelAttribute,@InitBinder标注的方法,设置RequestBodyAdvice和ResponseBodyAdvice类型的bean。
2、如果argumentResolvers为null,getDefaultArgumentResolvers添加默认参数值处理器
3、如果initBinderArgumentResolvers为空,getDefaultInitBinderArgumentResolvers添加InitBinder参数处理器
4、如果returnValueHandlers为空,调用getDefaultReturnValueHandlers添加默认返回值处理器

RequestMappingHandlerAdapter.initControllerAdviceCache()

private void initControllerAdviceCache() {
	if (getApplicationContext() == null) {
		return;
	}

	List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());

	List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();

	for (ControllerAdviceBean adviceBean : adviceBeans) {
		Class<?> beanType = adviceBean.getBeanType();
		if (beanType == null) {
			throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
		}
		Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
		if (!attrMethods.isEmpty()) {
			this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
		}
		Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
		if (!binderMethods.isEmpty()) {
			this.initBinderAdviceCache.put(adviceBean, binderMethods);
		}
		if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
			requestResponseBodyAdviceBeans.add(adviceBean);
		}
	}

	if (!requestResponseBodyAdviceBeans.isEmpty()) {
		this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
	}

	if (logger.isDebugEnabled()) {
		int modelSize = this.modelAttributeAdviceCache.size();
		int binderSize = this.initBinderAdviceCache.size();
		int reqCount = getBodyAdviceCount(RequestBodyAdvice.class);
		int resCount = getBodyAdviceCount(ResponseBodyAdvice.class);
		if (modelSize == 0 && binderSize == 0 && reqCount == 0 && resCount == 0) {
			logger.debug("ControllerAdvice beans: none");
		}
		else {
			logger.debug("ControllerAdvice beans: " + modelSize + " @ModelAttribute, " + binderSize +
					" @InitBinder, " + reqCount + " RequestBodyAdvice, " + resCount + " ResponseBodyAdvice");
		}
	}
}

1、findAnnotatedBeans在ApplicationContext查找@ControllerAdvice标注的bean,并以List返回
2、第一步的List,
如果bean没有@RequestMapping标注,有@ModelAttribute标注的Method,则将bean为key,Method集合(Set类型)为value加入modelAttributeAdviceCache。
如果bean有@InitBinder标注的方法则将bean为key,Method集合(Set类型)为value加入initBinderAdviceCache。
如果bean类型是RequestBodyAdvice或ResponseBodyAdvice则将bean加入requestResponseBodyAdviceBeans集合
3、如果requestResponseBodyAdviceBeans集合非空,则将requestResponseBodyAdviceBeans加入requestResponseBodyAdvice属性

RequestMappingHandlerAdapter.getDefaultArgumentResolvers()

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
	List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(30);

	// Annotation-based argument resolution
	resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
	resolvers.add(new RequestParamMapMethodArgumentResolver());
	resolvers.add(new PathVariableMethodArgumentResolver());
	resolvers.add(new PathVariableMapMethodArgumentResolver());
	resolvers.add(new MatrixVariableMethodArgumentResolver());
	resolvers.add(new MatrixVariableMapMethodArgumentResolver());
	resolvers.add(new ServletModelAttributeMethodProcessor(false));
	resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
	resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
	resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
	resolvers.add(new RequestHeaderMapMethodArgumentResolver());
	resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
	resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
	resolvers.add(new SessionAttributeMethodArgumentResolver());
	resolvers.add(new RequestAttributeMethodArgumentResolver());

	// Type-based argument resolution
	resolvers.add(new ServletRequestMethodArgumentResolver());
	resolvers.add(new ServletResponseMethodArgumentResolver());
	resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
	resolvers.add(new RedirectAttributesMethodArgumentResolver());
	resolvers.add(new ModelMethodProcessor());
	resolvers.add(new MapMethodProcessor());
	resolvers.add(new ErrorsMethodArgumentResolver());
	resolvers.add(new SessionStatusMethodArgumentResolver());
	resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
	if (KotlinDetector.isKotlinPresent()) {
		resolvers.add(new ContinuationHandlerMethodArgumentResolver());
	}

	// Custom arguments
	if (getCustomArgumentResolvers() != null) {
		resolvers.addAll(getCustomArgumentResolvers());
	}

	// Catch-all
	resolvers.add(new PrincipalMethodArgumentResolver());
	resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
	resolvers.add(new ServletModelAttributeMethodProcessor(true));

	return resolvers;
}

添加方法参数处理器。

RequestMappingHandlerAdapter.getDefaultInitBinderArgumentResolvers()

private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {
	List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(20);

	// Annotation-based argument resolution
	resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
	resolvers.add(new RequestParamMapMethodArgumentResolver());
	resolvers.add(new PathVariableMethodArgumentResolver());
	resolvers.add(new PathVariableMapMethodArgumentResolver());
	resolvers.add(new MatrixVariableMethodArgumentResolver());
	resolvers.add(new MatrixVariableMapMethodArgumentResolver());
	resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
	resolvers.add(new SessionAttributeMethodArgumentResolver());
	resolvers.add(new RequestAttributeMethodArgumentResolver());

	// Type-based argument resolution
	resolvers.add(new ServletRequestMethodArgumentResolver());
	resolvers.add(new ServletResponseMethodArgumentResolver());

	// Custom arguments
	if (getCustomArgumentResolvers() != null) {
		resolvers.addAll(getCustomArgumentResolvers());
	}

	// Catch-all
	resolvers.add(new PrincipalMethodArgumentResolver());
	resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));

	return resolvers;
}

添加@InitBinder方法参数处理器

RequestMappingHandlerAdapter.getDefaultReturnValueHandlers

private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
	List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(20);

	// Single-purpose return value types
	handlers.add(new ModelAndViewMethodReturnValueHandler());
	handlers.add(new ModelMethodProcessor());
	handlers.add(new ViewMethodReturnValueHandler());
	handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),
			this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
	handlers.add(new StreamingResponseBodyReturnValueHandler());
	handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
			this.contentNegotiationManager, this.requestResponseBodyAdvice));
	handlers.add(new HttpHeadersReturnValueHandler());
	handlers.add(new CallableMethodReturnValueHandler());
	handlers.add(new DeferredResultMethodReturnValueHandler());
	handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));

	// Annotation-based return value types
	handlers.add(new ServletModelAttributeMethodProcessor(false));
	handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
			this.contentNegotiationManager, this.requestResponseBodyAdvice));

	// Multi-purpose return value types
	handlers.add(new ViewNameMethodReturnValueHandler());
	handlers.add(new MapMethodProcessor());

	// Custom return value types
	if (getCustomReturnValueHandlers() != null) {
		handlers.addAll(getCustomReturnValueHandlers());
	}

	// Catch-all
	if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
		handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
	}
	else {
		handlers.add(new ServletModelAttributeMethodProcessor(true));
	}

	return handlers;
}

添加返回值处理器。

标签:resolvers,handlers,SpringMVC,List,add,源码,RequestMappingHandlerAdapter,new
From: https://www.cnblogs.com/shigongp/p/16855670.html

相关文章

  • SpringMVC中的@RestController
    在Spring中@RestController的作用等同于@Controller+@ResponseBody。所以想要理解@RestController注解就要先了解@Controller和@ResponseBody注解。@Controller之前已......
  • SpringMVC中Controller的运用
    Controller的运用通常通过接口和注解的方式实现第一种:实现Controller接口,Controller是一个接口,在org.springframework.web.servlet.mvc包下,接口中只有一个方法;编写一个Co......
  • springmvc-handlerInterceptor
    HandlerInterceptor接口给我们提供了3个方法:(1)preHandle:在执行controller处理之前执行,返回值为boolean,返回值为true时接着执行postHandle和afterCompletion,如果我们返......
  • 详解AQS中的condition源码原理
    摘要:condition用于显式的等待通知,等待过程可以挂起并释放锁,唤醒后重新拿到锁。本文分享自华为云社区《AQS中的condition源码原理详细分析》,作者:breakDawn。condition的用......
  • RockyLinux9 源码安装LNMP
    本文参考来自https://www.ziruchu.com/art/401在基础上修改了部分路径和版本,感谢原作者的分享。准备工作安装软件dnfinstall-ywgetvimlrzsz关闭防火墙#关闭防......
  • 《神经网络与深度学习》最新2018版中英PDF+源码
    机器学习AI算法工程 公众号:datayx资料获取1.关注微信公众号datayx 然后回复 深度学习即可获取。不断更新资源深度学习、机器学习、数据分析、python搜索公众号添加: ......
  • spring-boot-2.0.3启动源码篇四 - run方法(三)之createApplicationContext
    前言此系列是针对springboot的启动,旨在于和大家一起来看看springboot启动的过程中到底做了一些什么事。如果大家对springboot的源码有所研究,可以挑些自己感兴趣或者对自......
  • spring-boot-2.0.3启动源码篇三 - run方法(二)之prepareEnvironment
    前言此系列是针对springboot的启动,旨在于和大家一起来看看springboot启动的过程中到底做了一些什么事。如果大家对springboot的源码有所研究,可以挑些自己感兴趣或者对自......
  • spring-boot-2.0.3启动源码篇 - 阶段总结
    开心一刻朋友喜欢去按摩,第一次推门进来的是一个学生美眉,感觉还不错后来经常去,有时是护士,有时是空姐,有时候是教师昨天晚上推门进去的是一个女警察,长得贼好看,身材......
  • spring-boot-2.0.3启动源码篇五 - run方法(四)之prepareContext
    前言此系列是针对springboot的启动,旨在于和大家一起来看看springboot启动的过程中到底做了一些什么事。如果大家对springboot的源码有所研究,可以挑些自己感兴趣或者对自......