代码分析3 HandlerMethodArgumentResolver
1.@Requestbody
1.1谁是他的boss,看出来怎么生成的
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {private final List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>();private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache =new ConcurrentHashMap<>(256);
1.2.接口核心方法
- boolean supportsParameter(MethodParameter parameter);
Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,WebDataBinderFactory binderFactory**) throws **Exception;<br />做了两件事情,解析参数,
1.3.举例


解析参数

继续跟就是
AbstractJackson2HttpMessageConverter#
if (isUnicode) {return objectMapper.readValue(inputMessage.getBody(), javaType);}
2.无任何注解的对象
DispatcherServlet.doDispatch()
- 获得Handler
获得HandlerAdapter RequestMappingHandlerAdapter
- ServletInvocableHandlerMethod.invokeAndHandle(webRequest, mavContainer)
ServletInvocableHandlerMethod的字段resolvers->很多参数解析器
代码入口在这ServletInvocableHandlerMethodif (!this.resolvers.supportsParameter(parameter)) {throw new IllegalStateException());}try {args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);}
其实是ServletModelAttributeMethodProcessor

```java
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
……. // 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();
return attribute;}
ServletRequestDataBinder.bind```javaprotected void applyPropertyValues(MutablePropertyValues mpvs) {try {// Bind request parameters onto target object. 核心代码getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields());}catch (PropertyBatchUpdateException ex) {// Use bind error processor to create FieldErrors.for (PropertyAccessException pae : ex.getPropertyAccessExceptions()) {getBindingErrorProcessor().processPropertyAccessException(pae, getInternalBindingResult());}}}
转到这个对象了
@Overridepublic void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)throws BeansException {List<PropertyAccessException> propertyAccessExceptions = null;List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ?((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));if (ignoreUnknown) {this.suppressNotWritablePropertyException = true;}try {for (PropertyValue pv : propertyValues) {// setPropertyValue may throw any BeansException, which won't be caught// here, if there is a critical failure such as no matching field.// We can attempt to deal only with less serious exceptions.try {//核心代码setPropertyValue(pv);}catch (NotWritablePropertyException ex) {if (!ignoreUnknown) {throw ex;}// Otherwise, just ignore it and continue...}catch (NullValueInNestedPathException ex) {if (!ignoreInvalid) {throw ex;}// Otherwise, just ignore it and continue...}catch (PropertyAccessException ex) {if (propertyAccessExceptions == null) {propertyAccessExceptions = new ArrayList<>();}propertyAccessExceptions.add(ex);}}}finally {if (ignoreUnknown) {this.suppressNotWritablePropertyException = false;}}// If we encountered individual exceptions, throw the composite exception.if (propertyAccessExceptions != null) {PropertyAccessException[] paeArray = propertyAccessExceptions.toArray(new PropertyAccessException[0]);throw new PropertyBatchUpdateException(paeArray);}}
同类的方法
private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) {PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);if (ph == null || !ph.isWritable()) {if (pv.isOptional()) {if (logger.isDebugEnabled()) {logger.debug("Ignoring optional value for property '" + tokens.actualName +"' - property not found on bean class [" + getRootClass().getName() + "]");}return;}if (this.suppressNotWritablePropertyException) {// Optimization for common ignoreUnknown=true scenario since the// exception would be caught and swallowed higher up anyway...return;}throw createNotWritablePropertyException(tokens.canonicalName);}Object oldValue = null;try {Object originalValue = pv.getValue();Object valueToApply = originalValue;if (!Boolean.FALSE.equals(pv.conversionNecessary)) {if (pv.isConverted()) {valueToApply = pv.getConvertedValue();}else {if (isExtractOldValueForEditor() && ph.isReadable()) {try {oldValue = ph.getValue();}catch (Exception ex) {if (ex instanceof PrivilegedActionException) {ex = ((PrivilegedActionException) ex).getException();}if (logger.isDebugEnabled()) {logger.debug("Could not read previous value of property '" +this.nestedPath + tokens.canonicalName + "'", ex);}}}//转换核心代码valueToApply = convertForProperty(tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());}pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);}ph.setValue(valueToApply);}catch (TypeMismatchException ex) {throw ex;}catch (InvocationTargetException ex) {PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());if (ex.getTargetException() instanceof ClassCastException) {throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());}else {Throwable cause = ex.getTargetException();if (cause instanceof UndeclaredThrowableException) {// May happen e.g. with Groovy-generated methodscause = cause.getCause();}throw new MethodInvocationException(propertyChangeEvent, cause);}}catch (Exception ex) {PropertyChangeEvent pce = new PropertyChangeEvent(getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());throw new MethodInvocationException(pce, ex);}}
代码:
this.typeConverterDelegate.convertIfNecessary(propertyName, oldValue, newValue, requiredType, td);
org.springframework.beans.TypeConverterDelegate#convertIfNecessary(java.lang.String, java.lang.Object, java.lang.Object, java.lang.Class
(T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
GenericConversionService#convert(java.lang.Object, org.springframework.core.convert.TypeDescriptor, org.springframework.core.convert.TypeDescriptor)


底层是converter在帮我们做 对象的属性转换问题
挺复杂的,需要跟着代码去看,贴出来没啥意义
3.自定义converter

Cannot convert value of type ‘java.lang.String’ to required type ‘com.atguigu.demo.bean.Pet’ for property ‘pet’: no matching editors or conversion strategy found]
如果我们要扩展converter的话,可以参考配置类

默认会把对象的属性,一层一层的去解析很聪明,底层暂时没去看,有需要时候去看
3.解析HttpSession,Request这种原生的
ServletRequestMethodArgumentResolver
4.解析Model
ModelMethodProcessor
默认已经有2个属性了
参数是:
model=mavContainer.getModel()
来自ServletInvocableHandlerMethod
来自RequestMappingHandlerAdapter#invokeHandlerMethod的invocableMethod.invokeAndHandle(webRequest, mavContainer);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));modelFactory.initModel(webRequest, mavContainer, invocableMethod);mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
不是这里.再找找看 找到了
ServletInvocableHandlerMethod#resolveArgument
@Override@Nullablepublic final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {BindingResult bindingResult = null;attribute = createAttribute(...);出异常了就catch保存到bindingResult没出异常就WebDataBinder binder = binderFactory.createBinder(工厂模式new ExtendedServletRequestDataBinder 然后初始化);//核心逻辑绑定参数bindRequestParameters(binder);bindingResult = binder.getBindingResult();//真正赋值Map<String, Object> bindingResultModel = bindingResult.getModel();//这里也有逻辑mavContainer.removeAttributes(bindingResultModel);mavContainer.addAllAttributes(bindingResultModel);}



看看核心代码
ExtendedServletRequestDataBinderpublic void bind(ServletRequest request) {MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request);MultipartRequest multipartRequest = WebUtils.getNativeRequest(request, MultipartRequest.class);if (multipartRequest != null) {bindMultipart(multipartRequest.getMultiFileMap(), mpvs);}else if (StringUtils.startsWithIgnoreCase(request.getContentType(), "multipart/")) {HttpServletRequest httpServletRequest = WebUtils.getNativeRequest(request, HttpServletRequest.class);if (httpServletRequest != null) {StandardServletPartUtils.bindParts(httpServletRequest, mpvs, isBindEmptyMultipartFiles());}}addBindValues(mpvs, request);doBind(mpvs);}

@Overrideprotected void doBind(MutablePropertyValues mpvs) {checkFieldDefaults(mpvs);checkFieldMarkers(mpvs);adaptEmptyArrayIndices(mpvs);super.doBind(mpvs);}protected void doBind(MutablePropertyValues mpvs) {checkAllowedFields(mpvs);checkRequiredFields(mpvs);applyPropertyValues(mpvs);}protected void applyPropertyValues(MutablePropertyValues mpvs) {getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields());}
public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements BeanWrapper {@Overridepublic void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)throws BeansException {try {for (PropertyValue pv : propertyValues) {// setPropertyValue may throw any BeansException, which won't be caught// here, if there is a critical failure such as no matching field.// We can attempt to deal only with less serious exceptions.try {setPropertyValue(pv);}}}@Overridepublic void setPropertyValue(PropertyValue pv) throws BeansException {PropertyTokenHolder tokens = (PropertyTokenHolder) pv.resolvedTokens;if (tokens == null) {String propertyName = pv.getName();AbstractNestablePropertyAccessor nestedPa;try {nestedPa = getPropertyAccessorForPropertyPath(propertyName);}catch (NotReadablePropertyException ex) {throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,"Nested property in path '" + propertyName + "' does not exist", ex);}tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));if (nestedPa == this) {pv.getOriginalPropertyValue().resolvedTokens = tokens;}nestedPa.setPropertyValue(tokens, pv);}else {setPropertyValue(tokens, pv);}}
