(4).参数处理原理
路径跳转全在DispatcherServlet.java
这里
- HandlerMapping中找到能处理请求的Handler(Controller.method()) -》
请求的URL和请求方式
- 为当前Handler 找一个适配器 HandlerAdapter; RequestMappingHandlerAdapter -》
处理方法里面的参数和注解
- 适配器执行目标方法并确定方法参数的每一个值
(1.1)、HandlerAdapter
0 - 支持方法上标注@RequestMapping
1 - 支持函数式编程的
xxxxxx
(1.2)、执行目标方法
获取适配器
// Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
执行目标方法
// Actually invoke the handler. //DispatcherServlet -- doDispatch mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// RequestMappingHandlerAdapter 类 mav = invokeHandlerMethod(request, response, handlerMethod); //执行目标方法 //ServletInvocableHandlerMethod 类 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); //InvocableHandlerMethod 类 获取方法的参数值 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
(1.3)、参数解析器-HandlerMethodArgumentResolver
确定将要执行的目标方法的每一个参数的值是什么;
SpringMVC目标方法能写多少种参数类型。取决于参数解析器
。
- 当前解析器是否支持解析这种参数
- 支持就调用 resolveArgument
(1.4)、返回值处理器
(5).如何确定目标方法每一个参数的值
============InvocableHandlerMethod 类种 ========================== 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); } catch (Exception ex) { // Leave stack trace for later, exception may actually be resolved and handled... if (logger.isDebugEnabled()) { String exMsg = ex.getMessage(); if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) { logger.debug(formatArgumentError(parameter, exMsg)); } } throw ex; } } return args; }
假如说注解的参数不支持: "No suitable resolver"
(1.1)、挨个判断所有参数解析器那个支持解析这个参数
HandlerMethodArgumentResolverComposite 类 @Nullable private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) { HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter); if (result == null) { for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) { if (resolver.supportsParameter(parameter)) { result = resolver; this.argumentResolverCache.put(parameter, result); break; } } } return result; }
(1.2)、解析这个参数的值
InvocableHandlerMethod 类 进入这个方法 args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); 调用各自 HandlerMethodArgumentResolver 的 resolveArgument 方法即可
(1.3)、自定义类型参数 封装POJO
ServletModelAttributeMethodProcessor 这个参数处理器支持
是否为简单类型。
BeanUtils 类 /** * Check if the given type represents a "simple" value type: a primitive or * primitive wrapper, an enum, a String or other CharSequence, a Number, a * Date, a Temporal, a URI, a URL, a Locale, or a Class. * <p>{@code Void} and {@code void} are not considered simple value types. * @param type the type to check * @return whether the given type represents a "simple" value type * @see #isSimpleProperty(Class) */ public static boolean isSimpleValueType(Class<?> type) { return (Void.class != type && void.class != type && (ClassUtils.isPrimitiveOrWrapper(type) || Enum.class.isAssignableFrom(type) || CharSequence.class.isAssignableFrom(type) || Number.class.isAssignableFrom(type) || Date.class.isAssignableFrom(type) || Temporal.class.isAssignableFrom(type) || URI.class == type || URL.class == type || Locale.class == type || Class.class == type)); }
这里是将我们原来的request的值赋值给我们新创建的实列对象。
@Override @Nullable public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer"); Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory"); String name = ModelFactory.getNameForParameter(parameter); ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class); if (ann != null) { mavContainer.setBinding(name, ann.binding()); } Object attribute = null; BindingResult bindingResult = null; if (mavContainer.containsAttribute(name)) { attribute = mavContainer.getModel().get(name); } else { // Create attribute instance try { attribute = createAttribute(name, parameter, binderFactory, webRequest); } catch (BindException ex) { if (isBindExceptionRequired(parameter)) { // No BindingResult parameter -> fail with BindException throw ex; } // Otherwise, expose null/empty value and associated BindingResult if (parameter.getParameterType() == Optional.class) { attribute = Optional.empty(); } bindingResult = ex.getBindingResult(); } } if (bindingResult == null) { // Bean property binding and validation; // skipped in case of binding failure on construction. // 类型转换器 ⭐ WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name); if (binder.getTarget() != null) { if (!mavContainer.isBindingDisabled(name)) { // 开始赋值和转换 ⭐⭐ bindRequestParameters(binder, webRequest); } validateIfApplicable(binder, parameter); if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) { throw new BindException(binder.getBindingResult()); } } // Value type adaptation, also covering java.util.Optional if (!parameter.getParameterType().isInstance(attribute)) { attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter); } bindingResult = binder.getBindingResult(); } // Add resolved attribute and BindingResult at the end of the model Map<String, Object> bindingResultModel = bindingResult.getModel(); mavContainer.removeAttributes(bindingResultModel); mavContainer.addAllAttributes(bindingResultModel); return attribute; }