处理器适配器,主要是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);
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核心处理流程时序图:
【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。
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));
// 自定义的参数解析器
private List<HandlerMethodArgumentResolver> customArgumentResolvers;
// 框架内部的参数解析器
private HandlerMethodArgumentResolverComposite argumentResolvers;
// 标注了@InitBinder方法的参数解析器
private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;
// 自定义返回结果处理器
private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;
// 框架内部的返回结果处理器
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
// 框架内部视图解析器
private List<ModelAndViewResolver> modelAndViewResolvers;
// 框架内部内容协商管理器
private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();
// 信息转换器
private List<HttpMessageConverter<?>> messageConverters;
// 请求响应体通知/顾问器,主要用来在读取请求或者输出响应前做一些处理
private final List<Object> requestResponseBodyAdvice = new ArrayList<>();
// 数据绑定初始化器
private WebBindingInitializer webBindingInitializer;
private AsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("MvcAsync");
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
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方法。
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);
}
}
代码主要意思就是先初始化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
提供的方法,该方法很简洁-获取参数值然后反射调用目标方法。
public Object invokeForRequest(NativeWebRequest request, 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, 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
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 如下所示:
springframework.stereotype.Controller.
public class MyController implements Controller {
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类型
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
// 直接调用handler的handleRequest方法
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
// 如果是LastModified则调用其getLastModified方法,否则返回-1
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类型
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}
// 直接调用handlerd的handleRequest方法
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方法,仅仅只是转发了请求。
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
public boolean supports(Object handler) {
return (handler instanceof Servlet);
}
// 调用Servlet的service方法
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
((Servlet) handler).service(request, response);
return null;
}
// 直接返回-1
public long getLastModified(HttpServletRequest request, Object handler) {
return -1;
}
}
【5】HandlerFunctionAdapter
Spring5.2版本后新增的,主要为HandlerFunction服务。
// 判断是否为HandlerFunction类型
public boolean supports(Object handler) {
return handler instanceof HandlerFunction;
}
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;
}