处理器适配器,主要是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给子类实现
其supports方法对handler做了类型校验必须是HandlerMethod 类型,然后暴露抽象方法supportsInternal给子类实现 publi
其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<>();
构造函数如下所示在实例化时添加了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方法源码如下:
@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; }
③ 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都已经注入
③ 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,如果有合适的参数解析器则进行参数解析。
现在依次返回,我们看下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; }