SpringMVC源码解析系列3-HandleAdapter
HandleAdapter接口定义
定义: 根据HandlerMethod信息,对http请求进行参数解析,并完成调用
先看一下HandlerAdapter的接口定义
public interface HandlerAdapter { //判断是否支持该handler类型的解析 boolean supports(Object handler); //参数解析 并调用handler完成过程调用 ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; //用于处理http请求头中的last-modified long getLastModified(HttpServletRequest request, Object handler);}复制代码
RequestMappingHandlerAdapter
以RequestMappingHandlerAdapter为例来讲,先看下继承关系
初始化过程
同RequestMappingHandlerMapping都有ApplicationContextAware,ServletContextAware,InitializingBean三个生命周期方法
这里我们就直接看InitializingBean了
#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter@Overridepublic void afterPropertiesSet() { // 1.装载@ControllerAdvice注解的类 initControllerAdviceCache();// 2.装载ArgumentResolver(默认+自定义) if (this.argumentResolvers == null) { Listresolvers = getDefaultArgumentResolvers(); //包装成一个Composite对象 this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } // 2.装载InitBinderArgumentResolvers(默认+自定义) if (this.initBinderArgumentResolvers == null) { List resolvers = getDefaultInitBinderArgumentResolvers(); //包装成一个Composite对象 this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } // 3.装载ReturnValueHandlers(默认+自定义) if (this.returnValueHandlers == null) { List handlers = getDefaultReturnValueHandlers(); //包装成一个Composite对象 this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); }}复制代码
过程概括:
-
装载带有ControllerAdvices注解的对象
private void initControllerAdviceCache() { //从容器中获取所有带有ControllerAdvices注解的类名 并包装成ControllerAdviceBean List
beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext()); OrderComparator.sort(beans); List - 筛选出带有@ModelAttribute且不带@RequestMapping注解的方法
- 筛选出带InitBinder注解的方法 添加到initBinderAdviceCache中
- 筛选实现RequestBodyAdvice接口 添加到responseBodyAdvice中
- 筛选实现ResponseBodyAdvice接口 添加到responseBodyAdvice中
-
装载ArgumentResolvers(默认+自定义)
-
装载InitBinderArgumentResolvers(默认+自定义)
-
装载ReturnValueHandlers(默认+自定义)
自定义拓展方式放后面说
以下为HandlerAdapter默认解析器
HandlerMethodReturnValueHandler,HandlerMethodArgumentResolver
//参数解析器public interface HandlerMethodArgumentResolver { //判断是否支持该参数的解析(根据类型,注解等) boolean supportsParameter(MethodParameter parameter); //对参数进行解析 得到解析结果 Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;}//返回值解析器public interface HandlerMethodReturnValueHandler { //判断是否支持该返回值的解析(根据类型,注解等) boolean supportsReturnType(MethodParameter returnType); //对返回值进行解析 void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;}复制代码
DispatcherServlet调用HandlerAdapter过程
//1.调用support()方法判断是否支持HandlerMethod的解析HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// 如果是Get或Head请求 调用getLastModified()获取上次更新时间 String method = request.getMethod();boolean isGet = "GET".equals(method);if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } //如果小于浏览器缓存更新时间 则直接返回 浏览器使用本地缓存 if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; }}if (!mappedHandler.applyPreHandle(processedRequest, response)) { return;}// Actually invoke the handler.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());复制代码
过程总结:
-
调用support()方法判断是否支持改handler的解析
#org.springframework.web.servlet.DispatcherServlet//在doDispatch()方法中调用了getHandlerAdapter(Object)方法来得到一个HandlerAdapterprotected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { //调用HandlerAdapter.support()方法 判断是否支持该handler对象的解析 for (HandlerAdapter ha : this.handlerAdapters) { ... if (ha.supports(handler)) { return ha; } } ...}#org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter//根据handler对象判断是否支持handler解析@Overridepublic final boolean supports(Object handler) { return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));}#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter@Overrideprotected boolean supportsInternal(HandlerMethod handlerMethod) { return true;}复制代码
-
如果是Get或Head请求 调用getLastModified()获取上次更新时间
如果小于浏览器缓存更新时间 则直接返回 浏览器使用本地缓存
#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter@Overrideprotected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) { return -1;}复制代码
-
调用handler()方法完成过程调用(参数解析 返回值解析)
#org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter@Overridepublic final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handleInternal(request, response, (HandlerMethod) handler);}#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter@Overrideprotected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { //对http协议缓存方面的请求头的处理(expire,cache-control) if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true); }else { checkAndPrepare(request, response, true); } //是否使用session锁 if (this.synchronizeOnSession) { HttpSession session = request.getSession(false); if (session != null) { //得到互斥量 Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) {//执行过程调用 return invokeHandleMethod(request, response, handlerMethod); } } } //执行过程调用(参数解析 过程调用) return invokeHandleMethod(request, response, handlerMethod);}复制代码
参数解析,过程调用流程分析
//根据HandlerMethod解析参数 并完成过程调用得到一个ModelAndViewprivate ModelAndView invokeHandleMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); try { //对@InitBinder的处理 主要是聚合了@InitBinder的所有处理方法 WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); //@ModelAttribute的处理 ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); //对HandlerMethod的装饰,主要是增加了参数解析和返回值转化的功能 ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); //提供对参数解析的支持 invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); //提供对返回值解析的支持 invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); //提供对@InitBinder处理的支持 invocableMethod.setDataBinderFactory(binderFactory); //TODO 尚不明功能 invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); //可以看做handler()过程的上下文 ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); modelFactory.initModel(webRequest, mavContainer, invocableMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);==========================异步处理分割线============= //AsyncWebRequest内部持有AsyncContext 可以通过其开启异步任务 AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); asyncWebRequest.setTimeout(this.asyncRequestTimeout); //异步处理Manager 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(); ... //替换invocableMethod(原先异步处理的方法返回值是Callable现在直接返回结果) invocableMethod = invocableMethod.wrapConcurrentResult(result); } //对invocableMethod进行参数解析,过程调用,返回值转化 //并将结果存到mavContainer中 invocableMethod.invokeAndHandle(webRequest, mavContainer); //如果异步处理正在执行(已经开始,尚未结束) 立刻返回 //同时DispatcherServlet也直接返回 等待AsyncContext.dispatch()调用再次进入doDispatch()方法 if (asyncManager.isConcurrentHandlingStarted()) { return null; } //从mavContainer捞出结果 return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); }}复制代码
以上是invokeHandleMethod()的完整过程
但在调用过程中实际从异步处理分割线开始分为2种情况:
-
同步调用: 过程比较简单,直接进行参数解析和返回值转化就好了
invocableMethod.invokeAndHandle(webRequest, mavContainer);return getModelAndView(mavContainer, modelFactory, webRequest);复制代码
-
异步调用:
再分为两种情况:
-
异步处理中(已开始,尚未完成)
//AsyncWebRequest内部持有AsyncContext 可以通过其开启异步任务AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);asyncWebRequest.setTimeout(this.asyncRequestTimeout);//异步处理ManagerWebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);//设置异步执行线程池asyncManager.setTaskExecutor(this.taskExecutor);//提供对异步处理的支持asyncManager.setAsyncWebRequest(asyncWebRequest);//异步调用拦截器asyncManager.registerCallableInterceptors(this.callableInterceptors);asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);//对invocableMethod进行参数解析,过程调用(调用AsyncWebRequest.startAsync()执行异步过程),返回值转化//并将结果存到mavContainer中invocableMethod.invokeAndHandle(webRequest, mavContainer);//如果异步处理正在执行(已经开始,尚未结束) 立刻返回//同时DispatcherServlet也直接返回 return null;#org.springframework.web.servlet.DispatcherServletprotected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { ... mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } ...}//等待AsyncWebRequest.dispatch()被调用 然后再次进入doDispatch()方法复制代码
-
异步执行完成,再次进入doDispatch()流程
//AsyncWebRequest内部持有AsyncContext 可以通过其开启异步任务AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);asyncWebRequest.setTimeout(this.asyncRequestTimeout);//异步处理ManagerWebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);//设置异步执行线程池asyncManager.setTaskExecutor(this.taskExecutor);//提供对异步处理的支持asyncManager.setAsyncWebRequest(asyncWebRequest);//异步调用拦截器asyncManager.registerCallableInterceptors(this.callableInterceptors);asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);//异步处理完成 获取异步执行结果Object result = asyncManager.getConcurrentResult();mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];asyncManager.clearConcurrentResult();//替换invocableMethod(原先异步处理的方法返回值是Callable现在直接返回结果)invocableMethod = invocableMethod.wrapConcurrentResult(result);//对invocableMethod进行参数解析,过程调用,返回值转化//并将结果存到mavContainer中invocableMethod.invokeAndHandle(webRequest, mavContainer);//从mavContainer捞出结果return getModelAndView(mavContainer, modelFactory, webRequest);复制代码
-
ServletInvocableHandlerMethod
先看一下ServletInvocableHandlerMethod是个什么东东
HandlerMethod:保存了处理过程方法
InvocableHandlerMethod: 对HandlerMethod的装饰,增加了参数解析的功能
ServletInvocableHandlerMethod:对HandlerMethod的装饰,增加了返回值转化的功能
同步流程
-
invocableMethod.invokeAndHandle(webRequest, mavContainer);
#org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethodpublic void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 1.1 参数解析 并完成过程调用 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest); ... try { //1.2 使用returnValueHandlers对返回结果进行处理 讲结果塞到mavContainer中 过程类似参数解析 this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); }}#org.springframework.web.method.support.InvocableHandlerMethodpublic Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { //1.1.1 参数解析并得到绑定的结果 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); ... //1.1.2 反射完成过程调用 Object returnValue = doInvoke(args); ... return returnValue;}private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { //参数信息 MethodParameter[] parameters = getMethodParameters(); Object[] args = new Object[parameters.length]; for (int i = 0; i < parameters.length; i++) { //调用HandlerMethodArgumentResolver#supportsParameter判断是否支持该参数的解析 if (this.argumentResolvers.supportsParameter(parameter)) { try { //调用HandlerMethodArgumentResolver#resolveArgument进行解析 args[i] = this.argumentResolvers.resolveArgument( parameter, mavContainer, request, this.dataBinderFactory); continue; } ... } ... } return args;}复制代码
-
包装ModelAndView getModelAndView(mavContainer, modelFactory, webRequest);
//从mavContainer取出结果 包装成ModelAndViewprivate ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { modelFactory.updateModel(webRequest, mavContainer); if (mavContainer.isRequestHandled()) { return null; } ModelMap model = mavContainer.getModel(); ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model); if (!mavContainer.isViewReference()) { mav.setView((View) mavContainer.getView()); } //如果是redirect请求 if (model instanceof RedirectAttributes) { Map
flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } return mav;}复制代码
到此 HandlerAdapter.handler的调用过程算分析完了
@InitBinder的处理
WebDataBinder:数据(对象属性)绑定器,用于对对象的属性进行转化(Formatter)和校验(Validator)
InitBinder: @InitBinder注解用于在参数解析前初始化WebDataBinder.简单来说就是可以对WebDataBinder增加Validator和属性转化器Formatter
@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface InitBinder { //在哪些属性上发生作用 String[] value() default {};}复制代码
示例
@InitBinderprotected void initBinder(WebDataBinder binder) { //添加自定义Data类型Formatter SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); dateFormat.setLenient(false); binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));}复制代码
@InitBinder方法分为两种:
-
全局@InitBinder:定义在注解有@ControllerAdvices的类中,装载发生在HandlerAdapter初始化调用initControllerAdviceCache()过程中(见上文初始化过程分析)
-
局部@InitBinder:定义在注解有@Controller的类中,装载发生在HandlerAdapter.handler()调用getDataBinderFactory()过程中
private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception { //获取处理方法所在的类 Class handlerType = handlerMethod.getBeanType(); //从保存的全局缓存中找属于该类的局部@InitBinder方法 Set
methods = this.initBinderCache.get(handlerType); if (methods == null) { //如果没找到 说明该类不是一个@ControllerAdvices注解的类(只有@Controller没有@ControllerAdvices) //得到该类中所有@InitBinder注解的方法 methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS); //将局部@InitBinder方法缓存到initBinderCache中 this.initBinderCache.put(handlerType, methods); } List initBinderMethods = new ArrayList (); //将全局@InitBinder方法包装成InvocableHandlerMethod,添加到initBinderMethods for (Entry > entry : this.initBinderAdviceCache.entrySet()) { if (entry.getKey().isApplicableToBeanType(handlerType)) { Object bean = entry.getKey().resolveBean(); for (Method method : entry.getValue()) { initBinderMethods.add(createInitBinderMethod(bean, method)); } } } //将局部@InitBinder方法包装成InvocableHandlerMethod,添加到initBinderMethods for (Method method : methods) { Object bean = handlerMethod.getBean(); initBinderMethods.add(createInitBinderMethod(bean, method)); } //使用initBinderMethods对象(局部+全局),包装成WebDataBinderFactory对象 return createDataBinderFactory(initBinderMethods);}protected InitBinderDataBinderFactory createDataBinderFactory(List binderMethods) throws Exception { return new ServletRequestDataBinderFactory(binderMethods, getWebBindingInitializer());}复制代码
看完了了@InitBinder的装载过程,来看下@InitBinder方法是怎样被处理的
处理过程
this.argumentResolvers.resolveArgument( parameter, mavContainer, request, this.dataBinderFactory);复制代码
可以看到在使用argumentResolvers.resolveArgument()进行参数解析时将dataBinderFactory作为参数传递了过去
分别来看RequestParamMapMethodArgumentResolver,RequestResponseBodyMethodProcessor,ModelAttributeMethodProcessor三个参数解析器是如何处理@InitBinder方法的
-
RequestParamMapMethodArgumentResolver
@Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { // 完全没使用binderFactory ... }}复制代码
因为说过@InitBinder是用来初始化WebDataBinder的,而RequestParamMapMethodArgumentResolver是处理表单属性的(不是对象),所以完全没用
-
RequestResponseBodyMethodProcessor
@Overridepublic Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { parameter = parameter.nestedIfOptional(); //使用binderFactory创建对象解析器 WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name); if (arg != null) { //使用对象解析进行参数校验 validateIfApplicable(binder, parameter); //如果参数校验异常,且目标方法参数列表中没有BindingResult类型参数,则直接抛出参数解析异常 if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) { throw new MethodArgumentNotValidException(parameter, binder.getBindingResult()); } } //将参数解析结果存到mavContainer上下文中 mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult()); return adaptArgumentIfNecessary(arg, parameter);}复制代码
因为RequestResponseBodyMethodProcessor将属性绑定委托给了json解析器,所以这里WebDataBinder只负责参数校验
-
ModelAttributeMethodProcessor
@Overridepublic final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { String name = ModelFactory.getNameForParameter(parameter); Object attribute = (mavContainer.containsAttribute(name) ? mavContainer.getModel().get(name) : createAttribute(name, parameter, binderFactory, webRequest)); ... WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name); if (binder.getTarget() != null) { //使用binder进行属性绑定 if (!mavContainer.isBindingDisabled(name)) { bindRequestParameters(binder, webRequest); } //使用binder进行属性校验 validateIfApplicable(binder, parameter); if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) { throw new BindException(binder.getBindingResult()); } } // Add resolved attribute and BindingResult at the end of the model Map
bindingResultModel = binder.getBindingResult().getModel(); mavContainer.removeAttributes(bindingResultModel); mavContainer.addAllAttributes(bindingResultModel); return binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);}protected Object createAttribute(String attributeName, MethodParameter methodParam, WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception { return BeanUtils.instantiateClass(methodParam.getParameterType());}protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) { ((WebRequestDataBinder) binder).bind(request);}复制代码 使用WebDataBinder进行了属性绑定和属性校验