定义: 根据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为例来讲,先看下继承关系
同RequestMappingHandlerMapping都有 ApplicationContextAware , ServletContextAware , InitializingBean 三个生命周期方法
这里我们就直接看InitializingBean了
#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter @Override public void afterPropertiesSet() { // 1.装载@ControllerAdvice注解的类 initControllerAdviceCache(); // 2.装载ArgumentResolver(默认+自定义) if (this.argumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers(); //包装成一个Composite对象 this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } // 2.装载InitBinderArgumentResolvers(默认+自定义) if (this.initBinderArgumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers(); //包装成一个Composite对象 this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } // 3.装载ReturnValueHandlers(默认+自定义) if (this.returnValueHandlers == null) { List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers(); //包装成一个Composite对象 this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); } }
装载带有ControllerAdvices注解的对象
private void initControllerAdviceCache() { //从容器中获取所有带有ControllerAdvices注解的类名 并包装成ControllerAdviceBean List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext()); OrderComparator.sort(beans); List<Object> responseBodyAdviceBeans = new ArrayList<Object>(); for (ControllerAdviceBean bean : beans) { //筛选出带有@ModelAttribute且不带@RequestMapping注解的方法 Set<Method> attrMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS); if (!attrMethods.isEmpty()) { //保存到modelAttributeAdviceCache中 this.modelAttributeAdviceCache.put(bean, attrMethods); } //筛选出带InitBinder注解的方法 添加到initBinderAdviceCache中 Set<Method> binderMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS); if (!binderMethods.isEmpty()) { this.initBinderAdviceCache.put(bean, binderMethods); } //筛选实现RequestBodyAdvice接口 添加到requestResponseBodyAdviceBeans中 if (RequestBodyAdvice.class.isAssignableFrom(bean.getBeanType())) { requestResponseBodyAdviceBeans.add(bean); if (logger.isInfoEnabled()) { logger.info("Detected RequestBodyAdvice bean in " + bean); } } //筛选实现ResponseBodyAdvice接口 添加到requestResponseBodyAdviceBeans中 if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) { requestResponseBodyAdviceBeans.add(bean); if (logger.isInfoEnabled()) { logger.info("Detected ResponseBodyAdvice bean in " + bean); } } } //保存到全局变量 if (!responseBodyAdviceBeans.isEmpty()) { this.responseBodyAdvice.addAll(0, responseBodyAdviceBeans); } }
装载ArgumentResolvers(默认+自定义)
装载InitBinderArgumentResolvers(默认+自定义)
装载ReturnValueHandlers(默认+自定义)
自定义拓展方式放后面说
以下为HandlerAdapter默认解析器
//参数解析器 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; }
//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)方法来得到一个HandlerAdapter protected 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解析 @Override public final boolean supports(Object handler) { return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler)); } #org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter @Override protected boolean supportsInternal(HandlerMethod handlerMethod) { return true; }
如果是Get或Head请求 调用getLastModified()获取上次更新时间
如果小于浏览器缓存更新时间 则直接返回 浏览器使用本地缓存
#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter @Override protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) { return -1; }
调用handler()方法完成过程调用(参数解析 返回值解析)
#org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter @Override public 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 @Override protected 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解析参数 并完成过程调用得到一个ModelAndView private 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); //异步处理Manager WebAsyncManager 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.DispatcherServlet protected 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); //异步处理Manager WebAsyncManager 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是个什么东东
HandlerMethod:保存了处理过程方法
InvocableHandlerMethod: 对HandlerMethod的装饰,增加了参数解析的功能
ServletInvocableHandlerMethod:对HandlerMethod的装饰,增加了返回值转化的功能
invocableMethod.invokeAndHandle(webRequest, mavContainer);
#org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod public 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.InvocableHandlerMethod public 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取出结果 包装成ModelAndView private 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<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } return mav; }
到此 HandlerAdapter.handler的调用过程算分析完了
WebDataBinder:数据(对象属性)绑定器,用于对对象的属性进行转化(Formatter)和校验(Validator)
InitBinder: @InitBinder注解用于在参数解析前初始化WebDataBinder.简单来说就是可以对WebDataBinder增加Validator和属性转化器Formatter
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface InitBinder { //在哪些属性上发生作用 String[] value() default {}; }
@InitBinder protected 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<Method> 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<InvocableHandlerMethod> initBinderMethods = new ArrayList<InvocableHandlerMethod>(); //将全局@InitBinder方法包装成InvocableHandlerMethod,添加到initBinderMethods for (Entry<ControllerAdviceBean, Set<Method>> 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<InvocableHandlerMethod> 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
@Override public 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
@Override public 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<String, Object> 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进行了属性绑定和属性校验