SpringMVC源码(八):Controller控制器执行流程
在MVC请求流程中,获取到HandlerAdapter适配器后,会执行handler处理器(Controller控制器)的相关逻辑,通过适配器的handle()方法,完成目标Controller处理器的调用。在源码(七):HandlerAdapter适配器获取中提到,以HandlerAdapter为RequestMappingHandlerAdapter类型的为例,执行handler处理器(Controller控制器)的相关处理。
1、核心流程图
HandlerAdapter处理器适配器调用目标Controller控制器的方法逻辑的核心流程图:
2、核心流程源码分析
AbstractHandlerMethodAdapter#handle() 核心伪代码
1 // 处理目标handler处理器中的逻辑 2 public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) 3 throws Exception { 4 5 return handleInternal(request, response, (HandlerMethod) handler); 6 }
RequestMappingHandlerAdapter#handleInternal 核心伪代码
1 protected ModelAndView handleInternal(HttpServletRequest request, 2 HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { 3 4 // 执行Controller控制器的目标方法 5 ModelAndView mav = invokeHandlerMethod(request, response, handlerMethod); 6 7 // 返回执行结果ModeAndView 8 return mav; 9 }
RequestMappingHandlerAdapter#invokeHandlerMethod 核心伪代码
1 // 调用处理器的目标方法 2 protected ModelAndView invokeHandlerMethod(HttpServletRequest request, 3 HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { 4 5 // 使用request和response创建ServletWebRequest对象 6 ServletWebRequest webRequest = new ServletWebRequest(request, response); 7 try { 8 // 创建WebDataBinderFactory对象,此对象用来创建WebDataBinder对象,进行参数绑定, 9 WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); 10 11 // 创建ModelFactory对象,此对象主要用来处理model 12 // 主要是两个功能,1是在处理器具体处理之前对model进行初始化,2是在处理完请求后对model参数进行更新 13 ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); 14 15 // 创建ServletInvocableHandlerMethod对象,并设置其相关属性,实际的请求处理就是通过此对象来完成的,参数绑定、处理请求以及返回值处理都在此处完成 16 ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); 17 // 设置参数处理器 18 if (this.argumentResolvers != null) { 19 invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); 20 } 21 // 设置返回值处理器 22 if (this.returnValueHandlers != null) { 23 invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); 24 } 25 // 设置参数绑定工厂对象 26 invocableMethod.setDataBinderFactory(binderFactory); 27 // 设置参数名称发现器 28 invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); 29 30 // 创建ModelAndViewContainer对象,用于保存model和View对象 31 ModelAndViewContainer mavContainer = new ModelAndViewContainer(); 32 // 将flashmap中的数据设置到model中 33 mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); 34 // 使用modelFactory将sessionAttributes和注释了@ModelAttribute的方法的参数设置到model中 35 modelFactory.initModel(webRequest, mavContainer, invocableMethod); 36 // 根据配置对ignoreDefaultModelOnRedirect进行设置 37 mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); 38 39 // 创建AsyncWebRequest异步请求对象 40 AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); 41 asyncWebRequest.setTimeout(this.asyncRequestTimeout); 42 43 // 创建WebAsyncManager异步请求管理器对象 44 WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); 45 asyncManager.setTaskExecutor(this.taskExecutor); 46 asyncManager.setAsyncWebRequest(asyncWebRequest); 47 asyncManager.registerCallableInterceptors(this.callableInterceptors); 48 asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors); 49 50 // 如果当前异步请求已经处理并得到结果,则将返回的结果放到mavContainer对象中,然后将invocable对象进行包装转换,转成需要的执行对象然后开始执行 51 if (asyncManager.hasConcurrentResult()) { 52 Object result = asyncManager.getConcurrentResult(); 53 mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0]; 54 asyncManager.clearConcurrentResult(); 55 LogFormatUtils.traceDebug(logger, traceOn -> { 56 String formatted = LogFormatUtils.formatValue(result, !traceOn); 57 return "Resume with async result [" + formatted + "]"; 58 }); 59 // 转换具体的invocable执行对象 60 invocableMethod = invocableMethod.wrapConcurrentResult(result); 61 } 62 63 // 执行调用 64 invocableMethod.invokeAndHandle(webRequest, mavContainer); 65 if (asyncManager.isConcurrentHandlingStarted()) { 66 return null; 67 } 68 69 // 处理完请求后的后置处理 70 // 1、调用ModelFactory的updateModel方法更新model,包括设置SessionAttribute和给Model设置BinderResult 71 // 2、根据mavContainer创建了ModelAndView 72 // 3、如果mavContainer里的model是RedirectAttributes类型,则将其设置到FlashMap 73 return getModelAndView(mavContainer, modelFactory, webRequest); 74 } 75 finally { 76 // 标记请求完成 77 webRequest.requestCompleted(); 78 } 79 }
1、根据request、response创建ServletWebRequest对象
2、创建WebDataBinderFactory对象
创建WebDataBinderFactory对象,用于处理@InitBinder注解修饰的方法。
RequestMappingHandlerAdapter#getDataBinderFactory() 核心伪代码
1 // @InitBinder修饰方法缓存 2 private final Map<Class<?>, Set<Method>> initBinderCache = new ConcurrentHashMap<>(64); 3 4 // @InitBinder修饰方法过滤器 5 public static final MethodFilter INIT_BINDER_METHODS = method -> 6 AnnotatedElementUtils.hasAnnotation(method, InitBinder.class); 7 8 private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception { 9 // 获取当前handler的Class对象(Controller控制器的Class对象) 10 Class<?> handlerType = handlerMethod.getBeanType(); 11 // 检查当前Handler中的initBinder方法是否已经存在于缓存中 12 Set<Method> methods = this.initBinderCache.get(handlerType); 13 // 如果没有找到则查找并设置到缓冲中 14 if (methods == null) { 15 // 将当前Controller中所有被@InitBinder注解修饰的方法都获取到 16 methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS); 17 this.initBinderCache.put(handlerType, methods); 18 } 19 // 定义保存InitBinder方法的变量 20 List<InvocableHandlerMethod> initBinderMethods = new ArrayList<>(); 21 // 将所有符合条件的全局InitBinder方法添加到initBinderMethods 22 // 获取@ControllerAdvice注解修饰的类中被@InitBinder注解修饰的方法 23 this.initBinderAdviceCache.forEach((controllerAdviceBean, methodSet) -> { 24 if (controllerAdviceBean.isApplicableToBeanType(handlerType)) { 25 Object bean = controllerAdviceBean.resolveBean(); 26 for (Method method : methodSet) { 27 initBinderMethods.add(createInitBinderMethod(bean, method)); 28 } 29 } 30 }); 31 // 将当前handler中的initBinder方法添加到initBinderMethods 32 for (Method method : methods) { 33 // 创建当前方法对应的bean对象 34 Object bean = handlerMethod.getBean(); 35 // 将method适配为可执行的invocableHandlerMethod 36 initBinderMethods.add(createInitBinderMethod(bean, method)); 37 } 38 // 创建DataBinderFactory并返回 39 return createDataBinderFactory(initBinderMethods); 40 }
1、获取当前Controller中被@InitBinder修饰的方法。优先从initBinderCache缓存中获取,若缓存中不存在,则在当前Controller中查询,并将查询到的结果保存在methods集合中,并设置进initBinderCache缓存中。
2、获取全局(被@ControllerAdvice注解修饰的类)被@InitBinder注解修饰的方法,并将目标方法用InvocableHandlerMethod类型的对象封装,保存在initBinderMethods集合中。
3、遍历Controller中被被@InitBinder修饰的方法集合methods,将目标方法用InvocableHandlerMethod类型的对象封装,添加进initBinderMethods集合中。
4、创建WebDataBinderFactory类型的对象,将initBinderMethods集合设置到InitBinderDataBinderFactory的binderMethods属性中,返回WebDataBinderFactory类型的对象。
3、创建ModelFactory对象
创建WebDataBinderFactory对象,用于处理@ModelAttribute注解修饰的方法。RequestMappingHandlerAdapter#getModelFactory() 核心伪代码
1 // 被@ModelAttribute注解修饰的方法缓存 2 private final Map<Class<?>, Set<Method>> modelAttributeCache = new ConcurrentHashMap<>(64); 3 4 // 被@ModelAttribute修饰,未被@RequestMapping修饰的方法过滤器 5 public static final MethodFilter MODEL_ATTRIBUTE_METHODS = method -> 6 (!AnnotatedElementUtils.hasAnnotation(method, RequestMapping.class) && 7 AnnotatedElementUtils.hasAnnotation(method, ModelAttribute.class)); 8 9 // 被@ContollerAdvice注解修饰的类中,ModelAttribute方法 10 private final Map<ControllerAdviceBean, Set<Method>> modelAttributeAdviceCache = new LinkedHashMap<>(); 11 12 // 获取ModelFactory对象 13 private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) { 14 // 获取sessionAttributesHandler 15 SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod); 16 // 获取处理器类的类型 17 Class<?> handlerType = handlerMethod.getBeanType(); 18 // 从缓存中获取处理器类中注释了@ModelAttribute而且没有注释@RequestMapping的类 19 Set<Method> methods = this.modelAttributeCache.get(handlerType); 20 // 缓存中不存在 21 if (methods == null) { 22 // 从当前Controller中获取被@ModelAttribute注解修饰,未被@RequestMapping注解修饰的方法 23 methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS); 24 // 将方法设置进modelAttributeCache缓存中 25 this.modelAttributeCache.put(handlerType, methods); 26 } 27 // 定义保存ModelAttribute方法的变量 28 29 List<InvocableHandlerMethod> attrMethods = new ArrayList<>(); 30 31 // 先添加全局@ControllerAdvice的@ModelAttribute方法 32 this.modelAttributeAdviceCache.forEach((controllerAdviceBean, methodSet) -> { 33 if (controllerAdviceBean.isApplicableToBeanType(handlerType)) { 34 Object bean = controllerAdviceBean.resolveBean(); 35 // 将ModelAttribut方法用InvocableHandlerMethod类型对象封装,并添加进attrMethods中 36 for (Method method : methodSet) { 37 attrMethods.add(createModelAttributeMethod(binderFactory, bean, method)); 38 } 39 } 40 }); 41 // 再添加当前处理器Controller定义的@ModelAttribute方法 42 for (Method method : methods) { 43 Object bean = handlerMethod.getBean(); 44 attrMethods.add(createModelAttributeMethod(binderFactory, bean, method)); 45 } 46 // 新建ModelFactory对象 47 // 此处需要三个参数,第一个是被@ModelAttribute的方法,第二个是WebDataBinderFactory,第三个是SessionAttributeHandler 48 return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler); 49 }
1、获取当前Controller中被@ModelAttribute修饰,未被@RequestMapping修饰的方法。优先从modelAttributeCache缓存中获取,若缓存中不存在,则在当前Controller中查询,并将查询到的结果保存在methods集合中,并设置进modelAttributeCache缓存中。
2、获取全局(被@ControllerAdvice注解修饰的类)被@ModelAttribute注解修饰的方法,并将目标方法用InvocableHandlerMethod类型的对象封装,保存在attrMethods集合中。
3、遍历Controller中被@ModelAttribute修饰的方法集合methods,将目标方法用InvocableHandlerMethod类型的对象封装,添加进attrMethods集合中。
4、创建ModelFactory类型的对象,将attrMethods集合设置到ModeFaactory的modelMethods属性中,返回ModeFaactory类型的对象。
4、创建ServletInvocableHandlerMethod对象并完成属性设置
创建ServletInvocableHandlerMethod对象,用于调用Controller控制器中的目标方法逻辑。
4.1、创建ServletInvocableHandlerMethod对象
RequestMappingHandlerAdapter#createInvocableHandlerMethod() 核心伪代码
1 // 创建ServletInvocableHandlerMethod对象包装handlerMethod 2 protected ServletInvocableHandlerMethod createInvocableHandlerMethod(HandlerMethod handlerMethod) { 3 return new ServletInvocableHandlerMethod(handlerMethod); 4 }
4.2、属性设置
1 // 设置参数处理器 2 if (this.argumentResolvers != null) { 3 invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); 4 } 5 // 设置返回值处理器 6 if (this.returnValueHandlers != null) { 7 invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); 8 } 9 // 设置参数绑定工厂对象 10 invocableMethod.setDataBinderFactory(binderFactory); 11 // 设置参数名称发现器 12 invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
1、属性初始化
参数解析器argumentResolvers、返回值处理器returnValueHandlers的初始化过程与源码(六):Handler处理器获取中AbstractHandlerMethodMapping#mappingRegistry属性的初始化过程类似。
在MVC容器启动,创建MVC容器中单例的bean对象,创建RequestMappingHandlerAdapter的bean实例过程中,在getBean() -> doGetBean() -> createBean() -> doCreateBean() -> initializeBean() -> invokeInitMethods() -> RequestMappingHandlerAdapter#afterPropertiesSet()。
RequestMappingHandlerAdapter#afterPropertiesSet(),调用bean的afterPropertiesSet方法。
1 public void afterPropertiesSet() { 2 // 初始化ControllerAdvice缓存 3 initControllerAdviceCache(); 4 // 初始化参数处理器 - argumentResolvers 5 if (this.argumentResolvers == null) { 6 // 获取默认的参数处理器 7 List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers(); 8 this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); 9 } 10 // 初始化InitBinder方法参数处理器 - initBinderArgumentResolvers 11 if (this.initBinderArgumentResolvers == null) { 12 // 获取默认的InitBinder方法参数处理器 13 List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers(); 14 this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); 15 } 16 // 初始化返回值处理器 - returnValueHandlers 17 if (this.returnValueHandlers == null) { 18 // 获取默认的返回值处理器 19 List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers(); 20 this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); 21 } 22 }
1.1、参数处理器
初始化参数值处理器,,并将获取到的参数值处理器设置进HandlerMethodArgumentResolverComposite的argumentResolvers属性中,MVC容器中实现的默认参数值处理器如下:
获取默认返回值处理器器 RequestMappingHandlerAdapter#getDefaultArgumentResolvers() 核心伪代码
1 private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() { 2 List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(30); 3 4 // 基于注解的参数处理器 5 resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false)); 6 resolvers.add(new RequestParamMapMethodArgumentResolver()); 7 resolvers.add(new PathVariableMethodArgumentResolver()); 8 resolvers.add(new PathVariableMapMethodArgumentResolver()); 9 resolvers.add(new MatrixVariableMethodArgumentResolver()); 10 resolvers.add(new MatrixVariableMapMethodArgumentResolver()); 11 resolvers.add(new ServletModelAttributeMethodProcessor(false)); 12 resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice)); 13 resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice)); 14 resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory())); 15 resolvers.add(new RequestHeaderMapMethodArgumentResolver()); 16 resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory())); 17 resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory())); 18 resolvers.add(new SessionAttributeMethodArgumentResolver()); 19 resolvers.add(new RequestAttributeMethodArgumentResolver()); 20 21 // 基于类型的参数处理器 22 resolvers.add(new ServletRequestMethodArgumentResolver()); 23 resolvers.add(new ServletResponseMethodArgumentResolver()); 24 resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice)); 25 resolvers.add(new RedirectAttributesMethodArgumentResolver()); 26 resolvers.add(new ModelMethodProcessor()); 27 resolvers.add(new MapMethodProcessor()); 28 resolvers.add(new ErrorsMethodArgumentResolver()); 29 resolvers.add(new SessionStatusMethodArgumentResolver()); 30 resolvers.add(new UriComponentsBuilderMethodArgumentResolver()); 31 32 // 自定义参数解析器 33 if (getCustomArgumentResolvers() != null) { 34 resolvers.addAll(getCustomArgumentResolvers()); 35 } 36 37 // Catch-all 38 resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true)); 39 resolvers.add(new ServletModelAttributeMethodProcessor(true)); 40 41 return resolvers; 42 }
参数处理器的顶级接口HandlerMethodArgumentResolver包含两个核心方法:supportsParameter()、resolveArgument()
supportsParameter():判断是否支持参数解析方法;resolveArgument():具体的参数解析方法。
1 // 参数处理器接口 2 public interface HandlerMethodArgumentResolver { 3 4 // 当前参数处理器是否支持MethodParameter参数的解析 5 boolean supportsParameter(MethodParameter parameter); 6 7 // 从request请求中解析MethodParameter变成参数值并返回 8 Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, 9 NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception; 10 11 }
MVC容器中默认提供26种参数解析器:
1.2、返回值处理器
初始化返回值处理器,并将获取到的返回值处理器设置进HandlerMethodReturnValueHandlerComposite的returnValueHandlers属性中,MVC容器中实现的默认返回值处理器如下:
获取默认返回值处理器器 RequestMappingHandlerAdapter#getDefaultReturnValueHandlers() 核心伪代码
1 // 获取默认的返回值处理器 2 private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() { 3 // 保存返回值处理器集合 4 List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(20); 5 6 // 单一返回值处理器 7 handlers.add(new ModelAndViewMethodReturnValueHandler()); 8 handlers.add(new ModelMethodProcessor()); 9 handlers.add(new ViewMethodReturnValueHandler()); 10 handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(), 11 this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager)); 12 handlers.add(new StreamingResponseBodyReturnValueHandler()); 13 handlers.add(new HttpEntityMethodProcessor(getMessageConverters(), 14 this.contentNegotiationManager, this.requestResponseBodyAdvice)); 15 handlers.add(new HttpHeadersReturnValueHandler()); 16 handlers.add(new CallableMethodReturnValueHandler()); 17 handlers.add(new DeferredResultMethodReturnValueHandler()); 18 handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory)); 19 20 // 基于注解的返回值类型处理器 21 handlers.add(new ModelAttributeMethodProcessor(false)); 22 handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), 23 this.contentNegotiationManager, this.requestResponseBodyAdvice)); 24 25 // 多返回值处理器 26 handlers.add(new ViewNameMethodReturnValueHandler()); 27 handlers.add(new MapMethodProcessor()); 28 29 // 自定义返回值处理器 30 if (getCustomReturnValueHandlers() != null) { 31 handlers.addAll(getCustomReturnValueHandlers()); 32 } 33 34 // Catch-all 35 if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) { 36 handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers())); 37 } 38 else { 39 handlers.add(new ModelAttributeMethodProcessor(true)); 40 } 41 42 return handlers; 43 }
返回值处理器的顶级接口HandlerMethodReturnValueHandler包含两个核心方法:supportsReturnType()、handleReturnValue()
1 // 返回值处理器接口 2 public interface HandlerMethodReturnValueHandler { 3 4 // 是否支持当前返回值类型的处理 5 boolean supportsReturnType(MethodParameter returnType); 6 7 // 返回值参数解析 8 void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, 9 ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception; 10 11 }
MVC容器中默认提供15种参数解析器
2、设置参数处理器
1 // 设置参数处理器到ServletInvocableHandlerMethod的父类InvocableHandlerMethod中的resolvers属性 2 public void setHandlerMethodArgumentResolvers(HandlerMethodArgumentResolverComposite argumentResolvers) { 3 this.resolvers = argumentResolvers; 4 }
3、设置返回值处理器
将RequestMappingHandlerAdapter中的返回值处理器器属性returnValueHandlers设置到ServletInvocableHandlerMethod类型的对象中。
ServletInvocableHandlerMethod#returnValueHandlers() 核心代码:
1 // 设置返回值处理器到returnValueHandlers属性 2 public void setHandlerMethodReturnValueHandlers(HandlerMethodReturnValueHandlerComposite returnValueHandlers) { 3 this.returnValueHandlers = returnValueHandlers; 4 }
4、设置@InitBinder处理工厂
将获取到的WebDataBinderFactory设置到ServletInvocableHandlerMethod父类InvocableHandlerMethod中的dataBinderFactory属性中。
InvocableHandlerMethod#setDataBinderFactory() 核心代码:
1 // 设置@InitBinder处理工厂到ServletInvocableHandlerMethod的父类InvocableHandlerMethod中的dataBinderFactory属性 2 public void setDataBinderFactory(WebDataBinderFactory dataBinderFactory) { 3 this.dataBinderFactory = dataBinderFactory; 4 }
5、设置名称发现器
参数名称发现器parameterNameDiscoverer是RequestMappingHandlerAdapter中的属性,属性详情如下:
// 创建参数名称发现器 private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
在DefaultParameterNameDiscoverer构造函数中添加了名称发现器:KotlinReflectionParameterNameDiscoverer、StandardReflectionParameterNameDiscoverer、LocalVariableTableParameterNameDiscoverer
1 public DefaultParameterNameDiscoverer() { 2 if (KotlinDetector.isKotlinReflectPresent() && !GraalDetector.inImageCode()) { 3 addDiscoverer(new KotlinReflectionParameterNameDiscoverer()); 4 } 5 addDiscoverer(new StandardReflectionParameterNameDiscoverer()); 6 addDiscoverer(new LocalVariableTableParameterNameDiscoverer()); 7 }
5、创建ModelAndViewContainer对象并完成属性设置
ModelAndViewContainer对象的view和model属性:
1 public class ModelAndViewContainer { 2 3 // 是否不使用defaultModel属性标识 4 private boolean ignoreDefaultModelOnRedirect = false; 5 6 // ModelAndViewContainer的view属性 7 private Object view; 8 9 // ModelAndViewContainer的默认Model属性 10 private final ModelMap defaultModel = new BindingAwareModelMap(); 11 12 // ModelAndViewContainer的Model属性 13 private ModelMap redirectModel; 14 }
初始创建mavContainer对象,view属性和model属性为空,在执行完成handler处理器后,对view和model属性进行填充。
ModelAndViewContainer的model属性,BindingAwareModelMap类图如下,在实际填充ModelAndViewContainer的model属性,主要调用父类ExtendedModelMap、ModeMap中的方法,详细填充过程后续会进行分析。
6、调用handler执行器
调用handler执行器主要有三个步骤:请求参数解析、返回值结果解析、ModelAndViewContainer的Model属性、View属性填充。
ServletInvocableHandlerMethod #invokeAndHandle() 核心伪代码
1 // 调用处理Handler处理器 2 public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, 3 Object... providedArgs) throws Exception { 4 5 // 调用父类的invokeForRequest执行请求 6 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); 7 8 // 处理@ResponseStatus注解 9 setResponseStatus(webRequest); 10 // ... 11 // RequestHandled为false 即请求完成 12 mavContainer.setRequestHandled(false); 13 14 // 使用returnValueHandlers处理返回值 15 this.returnValueHandlers.handleReturnValue( 16 returnValue, getReturnValueType(returnValue), mavContainer, webRequest); 17 }
1、调用父类执行请求并获取返回结果
1 public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, 2 Object... providedArgs) throws Exception { 3 4 // 准备方法所需要的参数 5 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); 6 7 // 真正调用的method 8 return doInvoke(args); 9 }
1.1、获取方法参数getMethodArgumentValues
InvocableHandlerMethod#getMethodArgumentValues() 核心伪代码
1 protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, 2 Object... providedArgs) throws Exception { 3 4 // 获取方法的参数,HandlerMethod中的parameters属性 5 MethodParameter[] parameters = getMethodParameters(); 6 // 参数若为空,返回空参数数组 7 if (ObjectUtils.isEmpty(parameters)) { 8 return EMPTY_ARGS; 9 } 10 11 // 用于保存解析出参数的值 12 Object[] args = new Object[parameters.length]; 13 for (int i = 0; i < parameters.length; i++) { 14 MethodParameter parameter = parameters[i]; 15 // 给parameter设置参数名解析器 16 parameter.initParameterNameDiscovery(this.parameterNameDiscoverer); 17 // 如果相应类型的参数已经在providedArgs中提供了,则直接设置到parameter 18 args[i] = findProvidedArgument(parameter, providedArgs); 19 if (args[i] != null) { 20 continue; 21 } 22 // 若参数解析器无法解析参数,抛出异常 23 if (!this.resolvers.supportsParameter(parameter)) { 24 throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver")); 25 } 26 27 // 使用argumentResolvers参数解析器解析参数 28 args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); 29 30 } 31 return args; 32 }
1、方法为无参数方法,返回空参数数组
获取HandlerMethod中的parameters属性,在源码(六):Handler处理器获取中,有具体的HandlerMethod的获取过程,此处不再赘述。
2、方法为有参方法,解析参数
遍历方法参数,判断参数解析器集合中是否支持参数解析,若解析器集合不支持当前参数的解析,抛出异常,流程结束;若解析器集合支持当前参数的解析,调用参数解析器的resolveArgument()方法实现方法参数的解析,并将解析的结果放入args集合返回。
1.2、doInvoke -> 调用Controller控制器的指定方法
在执行完Controller控制器的处理逻辑后,已经填充了ModelAndViewContainer的defaultModel属性。
1、ModelAndViewContainer的model属性填充
1 // 设置ModleAndViewContainer的model属性 2 public ExtendedModelMap addAttribute(String attributeName, @Nullable Object attributeValue) { 3 // 添加属性 4 super.addAttribute(attributeName, attributeValue); 5 return this; 6 }
传入参数如下:
ModelMap#addAttribute() 核心伪代码
1 public ModelMap addAttribute(String attributeName, @Nullable Object attributeValue) { 2 // 设置属性名称、属性值 3 put(attributeName, attributeValue); 4 return this; 5 }
BindingAwareModelMap#put()
1 // 填充ModelAndViewContainer的Model属性 2 public Object put(String key, @Nullable Object value) { 3 // 清空重复的属性值、属性名称 4 removeBindingResultIfNecessary(key, value);、 5 // 填充属性 6 return super.put(key, value); 7 }
2、Controller控制器返回结果
2、返回结果的处理
处理Controller控制器返回结果,HandlerMethodReturnValueHandlerComposite#handleReturnValue 核心伪代码
1 // 处理Controller控制器返回结果 2 public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, 3 ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { 4 // 获取返回值处理器 5 HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); 6 // 未匹配到返回值处理器,抛出异常 7 if (handler == null) { 8 throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName()); 9 } 10 // 调用处理器处理返回值 11 handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); 12 }
1、匹配返回值处理器
1 // 获取返回值处理器 2 private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) { 3 // 异步处理返回值标识 4 boolean isAsyncValue = isAsyncReturnValue(value, returnType); 5 // 遍历返回值处理器 6 for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) { 7 // 若异步处理返回值标识为true并且当前返回值处理器不为AsyncHandlerMethodReturnValueHandler异步返回值处理器,跳过 8 if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) { 9 continue; 10 } 11 // 当前返回值处理器是否能处理Controller控制器返回结果 12 if (handler.supportsReturnType(returnType)) { 13 // 返回目标返回值处理器 14 return handler; 15 } 16 } 17 // 无匹配的返回值处理器,返回null 18 return null; 19 }
1、遍历MVC默认实现的返回值处理器
debug调试,获取返回值处理器ViewNameMethodReturnValueHandler,ViewNameMethodReturnValueHandler实现了返回值处理器的顶级接口HandlerMethodReturnValueHandler。
下面来看看ViewNameMethodReturnValueHandler对核心方法supportsReturnType()的实现, ViewNameMethodReturnValueHandler#supportsReturnType() 核心代码:
1 // 是否能处理返回值 2 public boolean supportsReturnType(MethodParameter returnType) { 3 // 获取返回值的类型 Class对象 4 Class<?> paramType = returnType.getParameterType();、 5 // ViewNameMethodReturnValueHandler可处理的返回值类型为void、CharSequence 6 return (void.class == paramType || CharSequence.class.isAssignableFrom(paramType)); 7 }
本次演示案例Contoller返回值为"userlist"为String类型,String实现了CharSequence接口,因此返回值处理器ViewNameMethodReturnValueHandler可处理String类型的返回结果。
2、调用处理器处理返回值
ViewNameMethodReturnValueHandler对核心方法supportsReturnType()的实现已经分析,下面来看看ViewNameMethodReturnValueHandler对返回值处理的核心方法handleReturnValue()的实现。
ViewNameMethodReturnValueHandler#handleReturnValue() 核心代码
1 // 处理器处理返回值结果 2 public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, 3 ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { 4 // 返回值类型为CharSequence类型 5 if (returnValue instanceof CharSequence) { 6 // 获取视图名称 7 String viewName = returnValue.toString(); 8 // 将视图名称设置进mavContainer对象的view属性 9 mavContainer.setViewName(viewName); 10 // 若为重定向视图,是指重定向标识为true 11 if (isRedirectViewName(viewName)) { 12 mavContainer.setRedirectModelScenario(true); 13 } 14 } 15 // 若返回值不为null。抛出异常 16 else if (returnValue != null) { 17 throw new UnsupportedOperationException("Unexpected return type: " + 18 returnType.getParameterType().getName() + " in method: " + returnType.getMethod()); 19 } 20 }
1、返回值类型为CharSequence,即字符串类型,获取返回视图名称,并将视图设置进ModelAndViewContainer中的view属性;
3、总结
7、获取ModelAndView对象
1 // 获取ModelAndView对象 2 private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, 3 ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { 4 5 // 更新model(设置sessionAttributes和给model设置BindingResult) 6 modelFactory.updateModel(webRequest, mavContainer); 7 // 若 mavContainer 已处理,则返回 null 8 if (mavContainer.isRequestHandled()) { 9 return null; 10 } 11 // 若 mavContainer未处理,基于mavContainer生成ModelAndView对象 12 ModelMap model = mavContainer.getModel(); 13 // 创建 ModelAndView 对象,并设置相关属性 14 ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus()); 15 16 // 如果mavContainer里的view不是string类型,强转为View类型,则设置到mv中 17 if (!mavContainer.isViewReference()) { 18 mav.setView((View) mavContainer.getView()); 19 } 20 // 重定向的处理 21 if (model instanceof RedirectAttributes) { 22 Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); 23 HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); 24 if (request != null) { 25 RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); 26 } 27 } 28 // 返回ModelAndView对象 29 return mav; 30 }
1、更新Model属性处理
ModelFactory#updateModel() 核心代码:
1 // Session属性处理器 2 private final SessionAttributesHandler sessionAttributesHandler; 3 4 // 更新Model属性 5 public void updateModel(NativeWebRequest request, ModelAndViewContainer container) throws Exception { 6 // 获取ModelAndViewContainer的Model属性 7 ModelMap defaultModel = container.getDefaultModel(); 8 // 判断ModelAndViewContainer中的SessionStatus是否为已完成 9 if (container.getSessionStatus().isComplete()){ 10 // 清理WebRequest请求中的attribute属性 11 this.sessionAttributesHandler.cleanupAttributes(request); 12 } 13 else { 14 // 将model属性设置到WebRequest请求 15 this.sessionAttributesHandler.storeAttributes(request, defaultModel); 16 } 17 // 请求是否未处理完成,ModelAndViewContainer中的model为默认的Model类型 18 if (!container.isRequestHandled() && container.getModel() == defaultModel) { 19 // 将数据绑定结果设置到Model属性中 20 updateBindingResult(request, defaultModel); 21 } 22 }
1.1、判断ModelAndViewContainer中的Session属性处理标识是否为已完成,若为已完成,则清除WebReqquest中的Session属性;若未完成,则将ModelAndViewContainer中的mode属性设置到WebRequest请求中。
1.2、Request请求未处理器完成,ModelAndViewContainer中的model为默认的Model类型,将数据绑定的结果设置到Model属性中。
2、ModelAndViewContainer请求处理判断
2.1、ModelAndViewContainer已处理,返回null
2.2、ModelAndViewContainer未处理
创建ModelAndView对象,并用ModelAndViewContainer对象中的Model属性、View属性初始化创建的ModelAndView对象。
1 // ModelAndView构造器 2 public ModelAndView(@Nullable String viewName, @Nullable Map<String, ?> model, @Nullable HttpStatus status) { 3 // 设置view视图 4 this.view = viewName; 5 // 设置model属性 6 if (model != null) { 7 getModelMap().addAllAttributes(model); 8 } 9 // 设置status状态 10 this.status = status; 11 }
如果mavContainer里的view不是string类型,强转为View类型,则设置到mv中;若mavContainer里的view是RedirectAttributes类型,获取重定向的属性值flashAttributes设置到WebRequest对象的attributes中,填充WebRequest对象。
3、Controller执行完成,返回ModelAndView对象