我是靠谱客的博主 奋斗航空,最近开发中收集的这篇文章主要介绍SpringMVC常见组件之HandlerAdapter分析【1】AbstractHandlerMethodAdapter【2】SimpleControllerHandlerAdapter【3】HttpRequestHandlerAdapter【4】SimpleServletHandlerAdapter【5】HandlerFunctionAdapter,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

处理器适配器,主要是DispatcherServlethandler之间的过渡/桥梁。简单来说就是DispatcherServlet根据handlerMapping创建一个处理器执行链对象HandlerExecutionChain。然后根据HandlerExecutionChain里面的handler来获取HandlerAdapter

HandlerAdapter调用handle方法处理请求。对DispatcherServlet来说,其不关心底层细节,只需要找到handler对应的HandlerAdapter然后交给HandlerAdapter即可。

为啥要HandlerAdapter呢? 适配器模式! 根据不同类型的handler在调用目标(方法)前进行相应处理。如果不用适配器,这部分相应处理就需要放到目标(方法)中。而根据接口设计原则,这是被反感的。

DispatcherServlet中,根据DispatcherServlet内部的handler获取HandlerAdapter

// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

当获取到请求对应的handlermapping以及HandlerExecutionChain(包含handler和interceptors)时,将根据handler和请求获取对应的HandlerAdapter来进行处理。如果找不到一个合适的HandlerAdapter(根据其supports方法判断),则抛出异常:

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
	if (this.handlerAdapters != null) {
		for (HandlerAdapter adapter : this.handlerAdapters) {
		    // 可以看到其是根据supports方法来抉择HandlerAdapter 
			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");
}

当获取到一个合适的HandlerAdapter后,会调用其handle方法进行实际的目标方法处理。 也就是说DispatcherServlet只关心下面这行代码,至于handler是什么,handler目标方法调用前需要做什么准备工作,DispatcherServlet概不关心,交给handler对应的HandlerAdapter处理。

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

需要注意的是,当xml中配置了<mvc:annotation-driven/>标签后,spring默认注入DefaultAnnotationHandlerMappingAnnotationMethodHandlerAdapter。该二者已过时,被RequestMappingHandlerMappingRequestMappingHandlerAdapter 替代。

HandlerAdapter提供的三个方法:

// 判断是否支持入参handler,也就是当前HandlerAdapter是否适用于入参handler
boolean supports(Object handler);

//使用给定的handler处理请求 返回响应--这是核心入口
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

// 最后修饰标记,如何不支持handler,则返回 -1
long getLastModified(HttpServletRequest request, Object handler);

在这里插入图片描述

idea里面操作:选中某个接口右键 -> Diagrams(show Diagram) -> 再出来的图上选中某个接口右键 ->show Implementations(或者Ctrl+T) ->出来的框框Ctrl + A ->Enter

适配器支持类型
AbstractHandlerMethodAdapterHandlerMethod
SimpleServletHandlerAdapterjavax.servlet.Servlet
SimpleControllerHandlerAdapterorg.springframework.web.servlet.mvc.Controller
HandlerFunctionAdapterorg.springframework.web.servlet.function.HandlerFunction
HttpRequestHandlerAdapterorg.springframework.web.HttpRequestHandler

如下是RequestMappingHandlerAdapter核心处理流程时序图:
在这里插入图片描述

【1】AbstractHandlerMethodAdapter

AbstractHandlerMethodAdapter主要用来处理Handler为HandlerMethod类型,也就是最常见的某个controller的某个方法。其只有一个子类RequestMappingHandlerAdapter

在这里插入图片描述
其supports方法对handler做了类型校验必须是HandlerMethod 类型,然后暴露抽象方法supportsInternal给子类实现

public final boolean supports(Object handler) {
	return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}

其handle方法也是暴露了抽象方法给子类实现handleInternal。

@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
		throws Exception {

	return handleInternal(request, response, (HandlerMethod) handler);
}

getLastModifiedInternal抽象方法给子类实现。

protected abstract long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod);

也就是说AbstractHandlerMethodAdapter本身没有实现HandlerAdapter的三个核心方法,交给了子类处理。

同时,我们也可以从其类结构图可以看到核心方法都是抽象方法,让唯一子类RequestMappingHandlerAdapter实现。
在这里插入图片描述

① RequestMappingHandlerAdapter的核心属性

// 是否忽略spring的xml配置,默认false
private static final boolean shouldIgnoreXml = SpringProperties.getFlag("spring.xml.ignore");

 // 找标注了@InitBinder方法
public static final MethodFilter INIT_BINDER_METHODS = method ->
		AnnotatedElementUtils.hasAnnotation(method, InitBinder.class);
		
// 找标注了 @ModelAttribute方法,但是没有标注@RequestMapping
public static final MethodFilter MODEL_ATTRIBUTE_METHODS = method ->
		(!AnnotatedElementUtils.hasAnnotation(method, RequestMapping.class) &&
				AnnotatedElementUtils.hasAnnotation(method, ModelAttribute.class));

// 自定义的参数解析器
@Nullable
private List<HandlerMethodArgumentResolver> customArgumentResolvers;

// 框架内部的参数解析器
@Nullable
private HandlerMethodArgumentResolverComposite argumentResolvers;

// 标注了@InitBinder方法的参数解析器
@Nullable
private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;

// 自定义返回结果处理器
@Nullable
private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;

// 框架内部的返回结果处理器
@Nullable
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;

// 框架内部视图解析器
@Nullable
private List<ModelAndViewResolver> modelAndViewResolvers;

// 框架内部内容协商管理器
private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();

// 信息转换器
private List<HttpMessageConverter<?>> messageConverters;

// 请求响应体通知/顾问器,主要用来在读取请求或者输出响应前做一些处理
private final List<Object> requestResponseBodyAdvice = new ArrayList<>();

// 数据绑定初始化器
@Nullable
private WebBindingInitializer webBindingInitializer;

private AsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("MvcAsync");

@Nullable
private Long asyncRequestTimeout;

private CallableProcessingInterceptor[] callableInterceptors = new CallableProcessingInterceptor[0];

private DeferredResultProcessingInterceptor[] deferredResultInterceptors = new DeferredResultProcessingInterceptor[0];

private ReactiveAdapterRegistry reactiveAdapterRegistry = ReactiveAdapterRegistry.getSharedInstance();

private boolean ignoreDefaultModelOnRedirect = false;

private int cacheSecondsForSessionAttributeHandlers = 0;

private boolean synchronizeOnSession = false;

private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore();

// 参数名发现/解析器
private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();

// beanFactory
@Nullable
private ConfigurableBeanFactory beanFactory;

// 如下是一些缓存
private final Map<Class<?>, SessionAttributesHandler> sessionAttributesHandlerCache = new ConcurrentHashMap<>(64);

private final Map<Class<?>, Set<Method>> initBinderCache = new ConcurrentHashMap<>(64);
// @ControllerAdvice类中的@InitBinder方法
private final Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache = new LinkedHashMap<>();

private final Map<Class<?>, Set<Method>> modelAttributeCache = new ConcurrentHashMap<>(64);

// @ControllerAdvice类中的@ModelAttribute方法
private final Map<ControllerAdviceBean, Set<Method>> modelAttributeAdviceCache = new LinkedHashMap<>();

构造函数如下所示在实例化时添加了ByteArrayHttpMessageConverterStringHttpMessageConverterSourceHttpMessageConverter以及AllEncompassingFormHttpMessageConverter

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());
}

② afterPropertiesSet

如下图所示,如何bean实现了InitializingBean接口,那么在初始化过程中一定会调用其afterPropertiesSet方法。
在这里插入图片描述
afterPropertiesSet方法源码如下:

@Override
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);
	}
}

代码主要意思就是先初始化ControllerAdviceCache,然后判断argumentResolversinitBinderArgumentResolvers 以及returnValueHandlers 是否为null,如果为null则获取系统内部的"对应的bean",然后放到XXXXXComposite中。

① initControllerAdviceCache

这里需要额外说明的是,如下是从系统内部全局扫描哦,也就是说modelAttributeAdviceCacheinitBinderAdviceCache以及requestResponseBodyAdviceBeans放的都是全局的。

private void initControllerAdviceCache() {
		if (getApplicationContext() == null) {
			return;
		}
// 获取标注了@ControllerAdvice注解的类,包装为ControllerAdviceBean,然后排序返回
		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);
			}
			// 获取系统内adviceBean 中的@ModelAttribute方法,然后放入modelAttributeAdviceCache
			Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
			if (!attrMethods.isEmpty()) {
				this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
			}
			// 获取系统内adviceBean 中的@InitBinder方法,然后放入initBinderAdviceCache
			Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
			if (!binderMethods.isEmpty()) {
				this.initBinderAdviceCache.put(adviceBean, binderMethods);
			}
// 获取系统内adviceBean 是RequestBodyAdvice或ResponseBodyAdvice类型,然后放入requestResponseBodyAdviceBeans
			if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
				requestResponseBodyAdviceBeans.add(adviceBean);
			}
		}

		if (!requestResponseBodyAdviceBeans.isEmpty()) {
			this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
		}
//... 一些日志打印 不用管
	
	}

代码解释如下:

  • ① 获取标注了@ControllerAdvice注解的类,包装为ControllerAdviceBean,然后排序返回List<ControllerAdviceBean> adviceBeans
  • ② 对adviceBeans进行遍历:
    • ③ 检索标注了@ModelAttribute注解的方法集合attrMethods,然后将(adviceBean, attrMethods)放入modelAttributeAdviceCache
    • ④ 检索标注了@InitBinder注解的方法集合binderMethods,然后将(adviceBean, binderMethods)放入initBinderAdviceCache
    • ⑤ 如果当前bean是RequestBodyAdvice或者ResponseBodyAdvice,则放入requestResponseBodyAdviceBeans
    • ⑥ 如果requestResponseBodyAdviceBeans不为空,则放入requestResponseBodyAdvice

② 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 RequestParamMethodArgumentResolver(getBeanFactory(), true));
	resolvers.add(new ServletModelAttributeMethodProcessor(true));

	return resolvers;
}

关于参数解析器,这里不展开分析,会放在参数解析器章节中说明。可以参考博文SpringMVC常见组件之HandlerMethodArgumentResolver解析

③ getDefaultInitBinderArgumentResolvers

这里是获取解析那些标注了@InitBinder方法的参数解析器

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;
}

④ 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;
}

这里我们同样不展开分析,放在返回结果处理器中说明。OK到这里我们的afterPropertiesSet完毕,也就是说bean实例化之后,需要的参数解析器、返回结果处理器以及标注了@ControllerAdvice的bean都已经注入。参考博文SpringMVC常见组件之HandlerMethodReturnValueHandler解析

③ handleInternal

RequestMappingHandlerAdaptersupportsInternal()方法很简单,直接返回了true。这里我们分析handleInternal方法。

protected ModelAndView handleInternal(HttpServletRequest request,
		HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

	ModelAndView mav;
	checkRequest(request);

	// Execute invokeHandlerMethod in synchronized block if required.
	if (this.synchronizeOnSession) {
		HttpSession session = request.getSession(false);
		if (session != null) {
			Object mutex = WebUtils.getSessionMutex(session);
			synchronized (mutex) {
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
			// No HttpSession available -> no mutex necessary
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}
	}
	else {
		// No synchronization on session demanded at all...
		mav = invokeHandlerMethod(request, response, handlerMethod);
	}

	if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
		if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
			applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
		}
		else {
			prepareResponse(response);
		}
	}

	return mav;
}

方法解释如下:

  • ① 检查请求,主要是检查supportedMethodsrequireSession。如果不满足可能会抛出HttpRequestMethodNotSupportedException或者HttpSessionRequiredException异常。
  • ② 判断是否需要同步锁,如果是且session不为null则获取锁再调用invokeHandlerMethod,否则直接调用invokeHandlerMethod
  • ③ 如果response的头部没有Cache-Control,则进行会话与缓存处理:
    • ④ 往Map<Class<?>, SessionAttributesHandler> sessionAttributesHandlerCache中放入BeanTypeSessionAttributesHandler
    • ⑤ 如果SessionAttributesHandlerSessionAttributes,则调用applyCacheSeconds方法否则直接调用prepareResponse(response);其实这两个方法都是对cacheControl、cacheSeconds进行处理。

SessionAttributesHandler 的核心属性和构造函数

public class SessionAttributesHandler {

	private final Set<String> attributeNames = new HashSet<>();

	private final Set<Class<?>> attributeTypes = new HashSet<>();

	private final Set<String> knownAttributeNames = Collections.newSetFromMap(new ConcurrentHashMap<>(4));

	private final SessionAttributeStore sessionAttributeStore;

	public SessionAttributesHandler(Class<?> handlerType, SessionAttributeStore sessionAttributeStore) {
		Assert.notNull(sessionAttributeStore, "SessionAttributeStore may not be null");
		this.sessionAttributeStore = sessionAttributeStore;

		SessionAttributes ann = AnnotatedElementUtils.findMergedAnnotation(handlerType, SessionAttributes.class);
		if (ann != null) {
			Collections.addAll(this.attributeNames, ann.names());
			Collections.addAll(this.attributeTypes, ann.types());
		}
		this.knownAttributeNames.addAll(this.attributeNames);
	}
	//...
}

① 核心方法invokeHandlerMethod

这个方法是springmvc请求流程中的核心入口方法,首先会进行一些bean的初始化,如binderFactorymodelFactoryinvocableMethodmavContainer、asyncWebRequest以及asyncManager。当准备工作做好之后,其会调用ServletInvocableHandlerMethod#invokeAndHandle方法进行目标方法的反射调用与返回结果处理。

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
		HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

	ServletWebRequest webRequest = new ServletWebRequest(request, response);
	try {
	//① 获取`WebDataBinderFactory`,这里获取的是`ServletRequestDataBinderFactory`
		WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
		//② 获取`ModelFactory`
		ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
//③ 将`handlerMethod`包装为`ServletInvocableHandlerMethod`
		ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
//④ 如果参数解析器不为null,则为`ServletInvocableHandlerMethod`设置`argumentResolvers`;
		if (this.argumentResolvers != null) {
			invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
		}
// ⑤ 如果返回结果处理器不为null,则为`ServletInvocableHandlerMethod`设置`returnValueHandlers`;
		if (this.returnValueHandlers != null) {
			invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
		}
		// ⑥ 设置binderFactory
		invocableMethod.setDataBinderFactory(binderFactory);
		invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
		// 实例化ModelAndViewContainer 并进行model初始化
		ModelAndViewContainer mavContainer = new ModelAndViewContainer();
		mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
		modelFactory.initModel(webRequest, mavContainer, invocableMethod);
		mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
		// 下面是异步请求处理的一些
		AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
		asyncWebRequest.setTimeout(this.asyncRequestTimeout);

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		asyncManager.setTaskExecutor(this.taskExecutor);
		asyncManager.setAsyncWebRequest(asyncWebRequest);
		asyncManager.registerCallableInterceptors(this.callableInterceptors);
		asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

		if (asyncManager.hasConcurrentResult()) {
			Object result = asyncManager.getConcurrentResult();
			mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
			asyncManager.clearConcurrentResult();
			LogFormatUtils.traceDebug(logger, traceOn -> {
				String formatted = LogFormatUtils.formatValue(result, !traceOn);
				return "Resume with async result [" + formatted + "]";
			});
			invocableMethod = invocableMethod.wrapConcurrentResult(result);
		}
		// 核心方法
		invocableMethod.invokeAndHandle(webRequest, mavContainer);
		if (asyncManager.isConcurrentHandlingStarted()) {
			return null;
		}
      // 获取ModelAndView,可能为null
		return getModelAndView(mavContainer, modelFactory, webRequest);
	}
	finally {
		webRequest.requestCompleted();
	}
}

代码解释如下:

  • ① 获取WebDataBinderFactory,这里获取的是ServletRequestDataBinderFactory,关于数据绑定器参考SpringMVC常见组件之DataBinder数据绑定器分析;这个过程会获取@InitBinder方法创建ServletRequestDataBinderFactory。
  • ② 获取ModelFactory,该工厂主要用来在方法调用前初始化model,方法调用后update model。会根据SessionAttributesHandlerModelAttributeMethod以及binderFactory来创建ModelFactory实例。这个过程会扫描获取@ModelAttribute方法哦;
  • ③ 将handlerMethod包装为ServletInvocableHandlerMethod,其继承自InvocableHandlerMethod,额外提供了返回结果处理能力(内部拥有HandlerMethodReturnValueHandlerComposite returnValueHandlers;成员变量);
  • ④ 如果参数解析器不为null,则为ServletInvocableHandlerMethod设置argumentResolvers
  • ⑤ 如果返回结果处理器不为null,则为ServletInvocableHandlerMethod设置returnValueHandlers
  • ⑥ 为ServletInvocableHandlerMethod设置DataBinderFactory
  • ⑦ 为ServletInvocableHandlerMethod设置ParameterNameDiscoverer,默认是DefaultParameterNameDiscoverer
  • ⑧ 实例化ModelAndViewContainer,其包括了defaultModel、redirectModel以及视图View;
  • ⑨ 往ModelAndViewContainerdefaultModel或者redirectModel添加“闪存属性”,闪存属性、redirectModel出现在请求重定向场景中。
  • ⑩ 初始化model,这里会获取sessionAttributes合并到model中,然后调用ModelAttributeMethods(就是标注了@ModelAttribute的方法),最后对sessionAttributes做校验(如果model中没有某个参数但是类注解@SessionAttributes中声明有,但是没有获取到值,那么会抛出异常HttpSessionRequiredException)。
  • 11 ModelAndViewContainer设置在重定向的时候是否忽略defaultModel,默认值false;
  • 12 一系列异步处理,应用在异步请求中…
  • 13 核心方法invocableMethod.invokeAndHandle(webRequest, mavContainer);,准备开始反射调用;
  • 14 getModelAndView(mavContainer, modelFactory, webRequest);获取ModelAndView,可能为null哦
  • 15 webRequest.requestCompleted();定义在finally中,最后处理请求结束,如更新session attributes。

② 核心方法getDataBinderFactory

这里我们看一下getDataBinderFactory方法,为什么特意分析呢?该方法在创建DataBinderFactory前会拿到全局initBinderAdviceCache"适合"当前handlerType的标注了@InitBinder的方法然后和当前handlerType中的标注了@InitBinder的方法一起构造为List<InvocableHandlerMethod> initBinderMethods提供给createDataBinderFactory(initBinderMethods);方法用来创建数据绑定器工厂。

private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
	Class<?> handlerType = handlerMethod.getBeanType();
	// 获取当前handlerType,其实就是controller中的标注了`@InitBinder`的方法
	Set<Method> methods = this.initBinderCache.get(handlerType);
	if (methods == null) {
		methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
		this.initBinderCache.put(handlerType, methods);
	}
	List<InvocableHandlerMethod> initBinderMethods = new ArrayList<>();
	// Global methods first
//拿到全局`initBinderAdviceCache`中`"适合"`当前`handlerType`的标注了`@InitBinder`的方法
	this.initBinderAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
		if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
			Object bean = controllerAdviceBean.resolveBean();
			for (Method method : methodSet) {
				initBinderMethods.add(createInitBinderMethod(bean, method));
			}
		}
	});
	for (Method method : methods) {
		Object bean = handlerMethod.getBean();
		initBinderMethods.add(createInitBinderMethod(bean, method));
	}
	return createDataBinderFactory(initBinderMethods);
}

③ 核心方法getModelFactory

同样的,在获取ModelFactory时候该方法在创建ModelFactory 前会拿到全局modelAttributeAdviceCache"适合"当前handlerType的标注了@ModelAttribute的方法然后和当前handlerType中的标注了@ModelAttribute的方法一起构造为List<InvocableHandlerMethod> attrMethods 提供给new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);方法用来创建ModelFactory 。

private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
	SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
	Class<?> handlerType = handlerMethod.getBeanType();
	Set<Method> methods = this.modelAttributeCache.get(handlerType);
	if (methods == null) {
		methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
		this.modelAttributeCache.put(handlerType, methods);
	}
	List<InvocableHandlerMethod> attrMethods = new ArrayList<>();
	// Global methods first
	this.modelAttributeAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
		if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
			Object bean = controllerAdviceBean.resolveBean();
			for (Method method : methodSet) {
				attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
			}
		}
	});
	for (Method method : methods) {
		Object bean = handlerMethod.getBean();
		attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
	}
	return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
}

④ 核心方法ModelFactory.initModel

public void initModel(NativeWebRequest request, ModelAndViewContainer container, HandlerMethod handlerMethod)
		throws Exception {
	//获取SessionAttributesHandler.knownAttributeNames中在session里面不为null的属性
	Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
	//合并值不为null的,且container中的model不包含该key的属性
	container.mergeAttributes(sessionAttributes);
	// 调用@ModelAttribute方法
	invokeModelAttributeMethods(request, container);
	// 检测
	for (String name : findSessionAttributeArguments(handlerMethod)) {
		if (!container.containsAttribute(name)) {
			Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
			if (value == null) {
				throw new HttpSessionRequiredException("Expected session attribute '" + name + "'", name);
			}
			container.addAttribute(name, value);
		}
	}
}

为什么这里我们会细致看一下这个方法呢?前面checkRequest(request);只是一种宏观的请求过滤,而initModel方法中呢,会对复杂对象类型的name-value做进一步过滤,这里可能会抛出HttpSessionRequiredException异常。

findSessionAttributeArguments如下所示从方法参数中找到标注了@ModelAttribute注解的参数,如果这个参数(或类型)是@SessionAttributes中标注的,则放到result中返回。

private List<String> findSessionAttributeArguments(HandlerMethod handlerMethod) {
	List<String> result = new ArrayList<>();
	for (MethodParameter parameter : handlerMethod.getMethodParameters()) {
		if (parameter.hasParameterAnnotation(ModelAttribute.class)) {
			String name = getNameForParameter(parameter);
			Class<?> paramType = parameter.getParameterType();
			if (this.sessionAttributesHandler.isHandlerSessionAttribute(name, paramType)) {
				result.add(name);
			}
		}
	}
	return result;
}

也就是说如果handlerMethod的参数中有使用了@ModelAttribute注解的参数且其是"SessionAttribute属性"(this.sessionAttributesHandler.isHandlerSessionAttribute(name, paramType))。如果ModelAndViewContainer 不包含该属性但是SessionAttributesHandler(内部的knownAttributeNames)包含该属性但是获取到的值为null,则抛出异常。

⑤ 核心方法invokeAndHandle

ServletInvocableHandlerMethod#invokeAndHandle方法主要是调用目标方法获取返回结果并对返回结果进行处理。

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
		Object... providedArgs) throws Exception {

	// 这里业务代码可能抛出异常,那么将会一路抛出到dispatchServlet中
	Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
	
	// 设置响应状态,如果HttpStatus不为null的话
	setResponseStatus(webRequest);

	if (returnValue == null) {
	// 判断请求是否未修改、响应状态是否不为null、请求是否已经被处理
		if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
		// 如果有必要则禁用内容缓存
			disableContentCachingIfNecessary(webRequest);
			// 设置请求被处理完毕
			mavContainer.setRequestHandled(true);
			return;
		}
	}else if (StringUtils.hasText(getResponseStatusReason())) {
		mavContainer.setRequestHandled(true);//是否有responseStatusReason,如果有设置请求已处理
		return;
	}
// 设置请求还没有被处理
	mavContainer.setRequestHandled(false);
	Assert.state(this.returnValueHandlers != null, "No return value handlers");
	try {
		this.returnValueHandlers.handleReturnValue( // 处理返回结果
				returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
	}
	catch (Exception ex) {
		if (logger.isTraceEnabled()) {
			logger.trace(formatErrorForReturnValue(returnValue), ex);
		}
		throw ex;
	}
}

代码解释如下:

  • invokeForRequest方法会解析参数然后反射调用目标方法获取返回结果;
  • ② 如果HttpStatus不为null,则setResponseStatus设置响应状态如状态码、状态说明;
  • ③ 如果返回结果为null或者ResponseStatusReason不为空,则尝试进行判断并处理webRequest和mavContainer,如mavContainer设置请求处理完毕状态标记为true。getResponseStatusgetResponseStatusReason常用在@ResponseStatus声明的方法场景中。
  • ④ 设置请求未被处理然后使用返回结果处理器处理返回结果。

可以看到该方法是一个模板方法,将具体功能抽离了出去,如invokeForRequesthandleReturnValue。关于返回结果处理这里不展开分析,会有单独章节说明。我们接下来继续追踪一下invokeForRequest方法。

⑥ 核心方法invokeForRequest

invokeForRequest方法是ServletInvocableHandlerMethod的父类InvocableHandlerMethod提供的方法,该方法很简洁-获取参数值然后反射调用目标方法。

@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
		Object... providedArgs) throws Exception {
	//获取解析到的参数值
	Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
	if (logger.isTraceEnabled()) {
		logger.trace("Arguments: " + Arrays.toString(args));
	}
	//反射调用方法获取方法返回结果
	return doInvoke(args);
}

这里核心在于getMethodArgumentValues,也就是解析参数值:

protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
		Object... providedArgs) throws Exception {

	MethodParameter[] parameters = getMethodParameters();
	if (ObjectUtils.isEmpty(parameters)) {
		return EMPTY_ARGS;
	}

	Object[] args = new Object[parameters.length];
	for (int i = 0; i < parameters.length; i++) {
		MethodParameter parameter = parameters[i];
		parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
		args[i] = findProvidedArgument(parameter, providedArgs);
		if (args[i] != null) {
			continue;
		}
		if (!this.resolvers.supportsParameter(parameter)) {
			throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
		}
		try {
			args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
		}
		//...
	}
	return args;
}

代码解释如下:

  • ① 获取方法参数数组,如果为空则返回new Object[0]
  • ② 遍历循环方法参数,如果未找到一个合适的参数解析器则抛出异常IllegalStateException,如果有合适的参数解析器则进行参数解析。

关于参数解析这里不展开分析,详情参考博文SpringMVC常见组件之HandlerMethodArgumentResolver解析单独章节说明。现在依次返回,我们看下getModelAndView方法。

⑦ 核心方法getModelAndView

@Nullable
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
		ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
	// 更新model
	modelFactory.updateModel(webRequest, mavContainer);
	// 很关键哦,表示请求已经处理,比如添加@ResponseBody注解的时候
	if (mavContainer.isRequestHandled()) {
		return null;
	}
	// 获取model,封装实例化ModelAndView 
	ModelMap model = mavContainer.getModel();
	ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
	if (!mavContainer.isViewReference()) {
		mav.setView((View) mavContainer.getView());
	}
	// 重定向请求时,如果有重定向属性 放到outputFlashMap中
	if (model instanceof RedirectAttributes) {
		Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
		HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
		if (request != null) {
			RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
		}
	}
	return mav;
}

代码解释如下 :

  • ① 更新model,这里会处理sessionAttributes(如clean或者store),然后尝试将BindingResult放到defaultModel中;
  • mavContainer.isRequestHandled()如果判断当前请求已经处理完毕,那么直接返回null;
  • ③ 获取ModelAndView 实例,包括Object view、ModelMap model、HttpStatus status;等。
  • ④ 如果view不是string,也就是经过解析的View,那么mav.setView((View) mavContainer.getView());
  • ⑤ 如果model是RedirectAttributes,也就是说当前请求是重定向。那么从model中获取"闪存"属性,然后放到HttpServletRequest 带给重定向后的请求域。

RedirectAttributes接口继承了Model接口,有唯一实现类RedirectAttributesModelMap
在这里插入图片描述

【2】SimpleControllerHandlerAdapter

其主要是用来为那些实现了Controller接口的handler服务的。什么叫做实现了Controller接口的handler呢?我们可以回顾一下其使用方法。

<mvc:view-controller path="/" view-name="index"></mvc:view-controller>

或者如下配置定义一个SimpleUrlHandlerMapping:

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping" >
      <!--或者如下配置-->
      <property name="mappings">
          <value>
              /myController=myController
          </value>
      </property>
      <property name="order">
          <value>
              1
          </value>
      </property>
  </bean>

可以看到上面我们定义了一个order属性为1,这是为了避免被defaultServleHandler预先处理"/**" -> "org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler#0"
在这里插入图片描述

MyController 如下所示:

@org.springframework.stereotype.Controller
public class MyController implements Controller {

   @Override
   public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
       System.out.println(request.getParameterMap());
       System.out.println(response.getStatus());
       ModelAndView modelAndView = new ModelAndView();
       modelAndView.setViewName("success");
       return modelAndView;
   }
}

接下来我们看一下SimpleControllerHandlerAdapter源码,如下所示其异常简单,简洁干脆实现了HandlerAdapterd的三个方法,没有额外方法。

public class SimpleControllerHandlerAdapter implements HandlerAdapter {
	// 判断是否支持当前handler --判断handler是否为Controller类型
	@Override
	public boolean supports(Object handler) {
		return (handler instanceof Controller);
	}
	// 直接调用handler的handleRequest方法
	@Override
	@Nullable
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
	
		return ((Controller) handler).handleRequest(request, response);
	}
	// 如果是LastModified则调用其getLastModified方法,否则返回-1
	@Override
	public long getLastModified(HttpServletRequest request, Object handler) {
		if (handler instanceof LastModified) {
			return ((LastModified) handler).getLastModified(request);
		}
		return -1L;
	}
}

【3】HttpRequestHandlerAdapter

该适配器也很简单,主要是为HttpRequestHandler服务。比如DefaultServletHttpRequestHandler–默认处理器,ResourceHttpRequestHandler静态资源处理。

public class HttpRequestHandlerAdapter implements HandlerAdapter {
// 判断handler是否为HttpRequestHandler类型
	@Override
	public boolean supports(Object handler) {
		return (handler instanceof HttpRequestHandler);
	}
// 直接调用handlerd的handleRequest方法
	@Override
	@Nullable
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		((HttpRequestHandler) handler).handleRequest(request, response);
		return null;
	}

	// 如果是LastModified则调用其getLastModified方法,否则返回-1	@Override
	public long getLastModified(HttpServletRequest request, Object handler) {
		if (handler instanceof LastModified) {
			return ((LastModified) handler).getLastModified(request);
		}
		return -1L;
	}

}

这里我们看一下DefaultServletHttpRequestHandler的handleRequest方法,仅仅只是转发了请求。

@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {

	Assert.state(this.servletContext != null, "No ServletContext set");
	RequestDispatcher rd = this.servletContext.getNamedDispatcher(this.defaultServletName);
	if (rd == null) {
		throw new IllegalStateException("A RequestDispatcher could not be located for the default servlet '" +
				this.defaultServletName + "'");
	}
	rd.forward(request, response);
}

【4】SimpleServletHandlerAdapter

最基础也很必要的一个适配器,为Servlet服务,处理请求时直接调用servlet的service方法。

public class SimpleServletHandlerAdapter implements HandlerAdapter {
// 判断handler是否为Servlet
	@Override
	public boolean supports(Object handler) {
		return (handler instanceof Servlet);
	}
// 调用Servlet的service方法
	@Override
	@Nullable
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		((Servlet) handler).service(request, response);
		return null;
	}
// 直接返回-1
	@Override
	public long getLastModified(HttpServletRequest request, Object handler) {
		return -1;
	}

}

【5】HandlerFunctionAdapter

Spring5.2版本后新增的,主要为HandlerFunction服务。

// 判断是否为HandlerFunction类型
@Override
public boolean supports(Object handler) {
	return handler instanceof HandlerFunction;
}

@Nullable
@Override
public ModelAndView handle(HttpServletRequest servletRequest,
		HttpServletResponse servletResponse,
		Object handler) throws Exception {


	HandlerFunction<?> handlerFunction = (HandlerFunction<?>) handler;

	ServerRequest serverRequest = getServerRequest(servletRequest);
	ServerResponse serverResponse = handlerFunction.handle(serverRequest);

	return serverResponse.writeTo(servletRequest, servletResponse,
			new ServerRequestContext(serverRequest));
}
// 直接返回-1
public long getLastModified(HttpServletRequest request, Object handler) {
	return -1L;
}

最后

以上就是奋斗航空为你收集整理的SpringMVC常见组件之HandlerAdapter分析【1】AbstractHandlerMethodAdapter【2】SimpleControllerHandlerAdapter【3】HttpRequestHandlerAdapter【4】SimpleServletHandlerAdapter【5】HandlerFunctionAdapter的全部内容,希望文章能够帮你解决SpringMVC常见组件之HandlerAdapter分析【1】AbstractHandlerMethodAdapter【2】SimpleControllerHandlerAdapter【3】HttpRequestHandlerAdapter【4】SimpleServletHandlerAdapter【5】HandlerFunctionAdapter所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(62)

评论列表共有 0 条评论

立即
投稿
返回
顶部