处理器适配器,主要是​​DispatcherServlet​​​与​​handler​​​之间的​​过渡/桥梁​​​。简单来说就是​​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默认注入​​DefaultAnnotationHandlerMapping​​​ 和​​AnnotationMethodHandlerAdapter​​​。该二者已过时,被​​RequestMappingHandlerMapping​​​ 和​​RequestMappingHandlerAdapter​​ 替代。

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

SpringMVC常见组件之HandlerAdapter分析_handlerAdapter

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

适配器

支持类型

AbstractHandlerMethodAdapter

HandlerMethod

SimpleServletHandlerAdapter

javax.servlet.Servlet

SimpleControllerHandlerAdapter

org.springframework.web.servlet.mvc.Controller

HandlerFunctionAdapter

org.springframework.web.servlet.function.HandlerFunction

HttpRequestHandlerAdapter

org.springframework.web.HttpRequestHandler

如下是RequestMappingHandlerAdapter核心处理流程时序图:
SpringMVC常见组件之HandlerAdapter分析_ide_02

【1】AbstractHandlerMethodAdapter

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

SpringMVC常见组件之HandlerAdapter分析_handlerAdapter_03
其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​​​实现。
SpringMVC常见组件之HandlerAdapter分析_springmvc_04

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

构造函数如下所示在实例化时添加了​​ByteArrayHttpMessageConverter​​​、​​StringHttpMessageConverter​​​、​​SourceHttpMessageConverter​​​以及​​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方法。
SpringMVC常见组件之HandlerAdapter分析_ide_05
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​​​,然后判断​​argumentResolvers​​​ 、​​initBinderArgumentResolvers​​​ 以及​​returnValueHandlers​​​ 是否为null,如果为null则获取系统内部的​​"对应的bean"​​,然后放到XXXXXComposite中。

① initControllerAdviceCache

这里需要额外说明的是,如下是从系统内部全局扫描哦,也就是说​​modelAttributeAdviceCache​​​、​​initBinderAdviceCache​​​以及​​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

​RequestMappingHandlerAdapter​​​的​​supportsInternal()​​​方法很简单,直接返回了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;
}

方法解释如下:

  • ① 检查请求,主要是检查​​supportedMethods​​​与​​requireSession​​​。如果不满足可能会抛出​​HttpRequestMethodNotSupportedException​​​或者​​HttpSessionRequiredException​​异常。
  • ② 判断是否需要同步锁,如果是且session不为null则获取锁再调用​​invokeHandlerMethod​​​,否则直接调用​​invokeHandlerMethod​
  • ③ 如果response的头部没有​​Cache-Control​​,则进行会话与缓存处理:
  • ④ 往​​Map<Class<?>, SessionAttributesHandler> sessionAttributesHandlerCache​​​中放入​​BeanType​​​与​​SessionAttributesHandler​​;
  • ⑤ 如果​​SessionAttributesHandler​​​有​​SessionAttributes​​​,则调用​​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的初始化,如​​binderFactory​​​、​​modelFactory​​​、​​invocableMethod​​​、​​mavContainer​​​、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。会根据​​SessionAttributesHandler​​​、​​ModelAttributeMethod​​​以及​​binderFactory​​​来创建​​ModelFactory​​​实例。这个过程会扫描获取​​@ModelAttribute​​方法哦;
  • ③ 将​​handlerMethod​​​包装为​​ServletInvocableHandlerMethod​​​,其继承自​​InvocableHandlerMethod​​​,额外提供了返回结果处理能力(内部拥有​​HandlerMethodReturnValueHandlerComposite returnValueHandlers​​;成员变量);
  • ④ 如果参数解析器不为null,则为​​ServletInvocableHandlerMethod​​​设置​​argumentResolvers​​;
  • ⑤ 如果返回结果处理器不为null,则为​​ServletInvocableHandlerMethod​​​设置​​returnValueHandlers​​;
  • ⑥ 为​​ServletInvocableHandlerMethod​​​设置​​DataBinderFactory​​;
  • ⑦ 为​​ServletInvocableHandlerMethod​​​设置​​ParameterNameDiscoverer​​​,默认是​​DefaultParameterNameDiscoverer​​;
  • ⑧ 实例化​​ModelAndViewContainer​​,其包括了defaultModel、redirectModel以及视图View;
  • ⑨ 往​​ModelAndViewContainer​​​的​​defaultModel​​​或者​​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。​​getResponseStatus​​​和​​getResponseStatusReason​​​常用在​​@ResponseStatus​​声明的方法场景中。
  • ④ 设置请求未被处理然后使用返回结果处理器处理返回结果。

可以看到该方法是一个模板方法,将具体功能抽离了出去,如​​invokeForRequest​​​、​​handleReturnValue​​。关于返回结果处理这里不展开分析,会有单独章节说明。我们接下来继续追踪一下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​​​。
SpringMVC常见组件之HandlerAdapter分析_返回结果_06

【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"​​​SpringMVC常见组件之HandlerAdapter分析_springmvc_07

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