代码分析3 HandlerMethodArgumentResolver

1.@Requestbody

1.1谁是他的boss,看出来怎么生成的

  1. public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
  2. private final List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>();
  3. private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache =
  4. new ConcurrentHashMap<>(256);

1.2.接口核心方法

  • boolean supportsParameter(MethodParameter parameter);
  • Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,

    1. NativeWebRequest webRequest,WebDataBinderFactory binderFactory**) throws **Exception;<br />做了两件事情,解析参数,

    1.3.举例

image.png

image.png

解析参数
image.png
image.png
继续跟就是
AbstractJackson2HttpMessageConverter#

  1. if (isUnicode) {
  2. return objectMapper.readValue(inputMessage.getBody(), javaType);
  3. }

告一段落

2.无任何注解的对象

DispatcherServlet.doDispatch()

  • 获得Handler
  • 获得HandlerAdapter RequestMappingHandlerAdapter

    • ServletInvocableHandlerMethod.invokeAndHandle(webRequest, mavContainer)
    • ServletInvocableHandlerMethod的字段resolvers->很多参数解析器

      1. 代码入口在这ServletInvocableHandlerMethod
      2. if (!this.resolvers.supportsParameter(parameter)) {
      3. throw new IllegalStateException());
      4. }
      5. try {
      6. args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
      7. }

      其实是ServletModelAttributeMethodProcessor
      image.png
      image.png ```java public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,

      1. 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)) {

      1. bindRequestParameters(binder, webRequest);//核心代码在这

      } validateIfApplicable(binder, parameter); if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {

      1. 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();

  1. return attribute;
  2. }
  1. ServletRequestDataBinder.bind
  2. ```java
  3. protected void applyPropertyValues(MutablePropertyValues mpvs) {
  4. try {
  5. // Bind request parameters onto target object. 核心代码
  6. getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields());
  7. }
  8. catch (PropertyBatchUpdateException ex) {
  9. // Use bind error processor to create FieldErrors.
  10. for (PropertyAccessException pae : ex.getPropertyAccessExceptions()) {
  11. getBindingErrorProcessor().processPropertyAccessException(pae, getInternalBindingResult());
  12. }
  13. }
  14. }

转到这个对象了
image.png

  1. @Override
  2. public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
  3. throws BeansException {
  4. List<PropertyAccessException> propertyAccessExceptions = null;
  5. List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ?
  6. ((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));
  7. if (ignoreUnknown) {
  8. this.suppressNotWritablePropertyException = true;
  9. }
  10. try {
  11. for (PropertyValue pv : propertyValues) {
  12. // setPropertyValue may throw any BeansException, which won't be caught
  13. // here, if there is a critical failure such as no matching field.
  14. // We can attempt to deal only with less serious exceptions.
  15. try {
  16. //核心代码
  17. setPropertyValue(pv);
  18. }
  19. catch (NotWritablePropertyException ex) {
  20. if (!ignoreUnknown) {
  21. throw ex;
  22. }
  23. // Otherwise, just ignore it and continue...
  24. }
  25. catch (NullValueInNestedPathException ex) {
  26. if (!ignoreInvalid) {
  27. throw ex;
  28. }
  29. // Otherwise, just ignore it and continue...
  30. }
  31. catch (PropertyAccessException ex) {
  32. if (propertyAccessExceptions == null) {
  33. propertyAccessExceptions = new ArrayList<>();
  34. }
  35. propertyAccessExceptions.add(ex);
  36. }
  37. }
  38. }
  39. finally {
  40. if (ignoreUnknown) {
  41. this.suppressNotWritablePropertyException = false;
  42. }
  43. }
  44. // If we encountered individual exceptions, throw the composite exception.
  45. if (propertyAccessExceptions != null) {
  46. PropertyAccessException[] paeArray = propertyAccessExceptions.toArray(new PropertyAccessException[0]);
  47. throw new PropertyBatchUpdateException(paeArray);
  48. }
  49. }

同类的方法

  1. private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) {
  2. PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
  3. if (ph == null || !ph.isWritable()) {
  4. if (pv.isOptional()) {
  5. if (logger.isDebugEnabled()) {
  6. logger.debug("Ignoring optional value for property '" + tokens.actualName +
  7. "' - property not found on bean class [" + getRootClass().getName() + "]");
  8. }
  9. return;
  10. }
  11. if (this.suppressNotWritablePropertyException) {
  12. // Optimization for common ignoreUnknown=true scenario since the
  13. // exception would be caught and swallowed higher up anyway...
  14. return;
  15. }
  16. throw createNotWritablePropertyException(tokens.canonicalName);
  17. }
  18. Object oldValue = null;
  19. try {
  20. Object originalValue = pv.getValue();
  21. Object valueToApply = originalValue;
  22. if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
  23. if (pv.isConverted()) {
  24. valueToApply = pv.getConvertedValue();
  25. }
  26. else {
  27. if (isExtractOldValueForEditor() && ph.isReadable()) {
  28. try {
  29. oldValue = ph.getValue();
  30. }
  31. catch (Exception ex) {
  32. if (ex instanceof PrivilegedActionException) {
  33. ex = ((PrivilegedActionException) ex).getException();
  34. }
  35. if (logger.isDebugEnabled()) {
  36. logger.debug("Could not read previous value of property '" +
  37. this.nestedPath + tokens.canonicalName + "'", ex);
  38. }
  39. }
  40. }
  41. //转换核心代码
  42. valueToApply = convertForProperty(
  43. tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());
  44. }
  45. pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
  46. }
  47. ph.setValue(valueToApply);
  48. }
  49. catch (TypeMismatchException ex) {
  50. throw ex;
  51. }
  52. catch (InvocationTargetException ex) {
  53. PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(
  54. getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
  55. if (ex.getTargetException() instanceof ClassCastException) {
  56. throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());
  57. }
  58. else {
  59. Throwable cause = ex.getTargetException();
  60. if (cause instanceof UndeclaredThrowableException) {
  61. // May happen e.g. with Groovy-generated methods
  62. cause = cause.getCause();
  63. }
  64. throw new MethodInvocationException(propertyChangeEvent, cause);
  65. }
  66. }
  67. catch (Exception ex) {
  68. PropertyChangeEvent pce = new PropertyChangeEvent(
  69. getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
  70. throw new MethodInvocationException(pce, ex);
  71. }
  72. }

代码:
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, org.springframework.core.convert.TypeDescriptor)

(T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);

GenericConversionService#convert(java.lang.Object, org.springframework.core.convert.TypeDescriptor, org.springframework.core.convert.TypeDescriptor)

image.png
image.png
底层是converter在帮我们做 对象的属性转换问题

挺复杂的,需要跟着代码去看,贴出来没啥意义
3.自定义converter
image.png
image.png
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的话,可以参考配置类
image.png
image.png
默认会把对象的属性,一层一层的去解析很聪明,底层暂时没去看,有需要时候去看

3.解析HttpSession,Request这种原生的

ServletRequestMethodArgumentResolver
image.png

4.解析Model

ModelMethodProcessor
image.png
默认已经有2个属性了
参数是:
model=mavContainer.getModel()
来自ServletInvocableHandlerMethod
来自RequestMappingHandlerAdapter#invokeHandlerMethod的invocableMethod.invokeAndHandle(webRequest, mavContainer);

  1. ModelAndViewContainer mavContainer = new ModelAndViewContainer();
  2. mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
  3. modelFactory.initModel(webRequest, mavContainer, invocableMethod);
  4. mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

不是这里.再找找看 找到了
ServletInvocableHandlerMethod#resolveArgument

  1. @Override
  2. @Nullable
  3. public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
  4. NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
  5. BindingResult bindingResult = null;
  6. attribute = createAttribute(...);
  7. 出异常了就catch保存到bindingResult
  8. 没出异常就
  9. WebDataBinder binder = binderFactory.createBinder(工厂模式new ExtendedServletRequestDataBinder 然后初始化);
  10. //核心逻辑绑定参数
  11. bindRequestParameters(binder);
  12. bindingResult = binder.getBindingResult();
  13. //真正赋值
  14. Map<String, Object> bindingResultModel = bindingResult.getModel();//这里也有逻辑
  15. mavContainer.removeAttributes(bindingResultModel);
  16. mavContainer.addAllAttributes(bindingResultModel);
  17. }

image.png
image.png
image.png

看看核心代码
image.png

  1. ExtendedServletRequestDataBinder
  2. public void bind(ServletRequest request) {
  3. MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request);
  4. MultipartRequest multipartRequest = WebUtils.getNativeRequest(request, MultipartRequest.class);
  5. if (multipartRequest != null) {
  6. bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
  7. }
  8. else if (StringUtils.startsWithIgnoreCase(request.getContentType(), "multipart/")) {
  9. HttpServletRequest httpServletRequest = WebUtils.getNativeRequest(request, HttpServletRequest.class);
  10. if (httpServletRequest != null) {
  11. StandardServletPartUtils.bindParts(httpServletRequest, mpvs, isBindEmptyMultipartFiles());
  12. }
  13. }
  14. addBindValues(mpvs, request);
  15. doBind(mpvs);
  16. }

image.png

  1. @Override
  2. protected void doBind(MutablePropertyValues mpvs) {
  3. checkFieldDefaults(mpvs);
  4. checkFieldMarkers(mpvs);
  5. adaptEmptyArrayIndices(mpvs);
  6. super.doBind(mpvs);
  7. }
  8. protected void doBind(MutablePropertyValues mpvs) {
  9. checkAllowedFields(mpvs);
  10. checkRequiredFields(mpvs);
  11. applyPropertyValues(mpvs);
  12. }
  13. protected void applyPropertyValues(MutablePropertyValues mpvs) {
  14. getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields());
  15. }
  1. public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements BeanWrapper {
  2. @Override
  3. public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
  4. throws BeansException {
  5. try {
  6. for (PropertyValue pv : propertyValues) {
  7. // setPropertyValue may throw any BeansException, which won't be caught
  8. // here, if there is a critical failure such as no matching field.
  9. // We can attempt to deal only with less serious exceptions.
  10. try {
  11. setPropertyValue(pv);
  12. }
  13. }
  14. }
  15. @Override
  16. public void setPropertyValue(PropertyValue pv) throws BeansException {
  17. PropertyTokenHolder tokens = (PropertyTokenHolder) pv.resolvedTokens;
  18. if (tokens == null) {
  19. String propertyName = pv.getName();
  20. AbstractNestablePropertyAccessor nestedPa;
  21. try {
  22. nestedPa = getPropertyAccessorForPropertyPath(propertyName);
  23. }
  24. catch (NotReadablePropertyException ex) {
  25. throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
  26. "Nested property in path '" + propertyName + "' does not exist", ex);
  27. }
  28. tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
  29. if (nestedPa == this) {
  30. pv.getOriginalPropertyValue().resolvedTokens = tokens;
  31. }
  32. nestedPa.setPropertyValue(tokens, pv);
  33. }
  34. else {
  35. setPropertyValue(tokens, pv);
  36. }
  37. }