专业的编程技术博客社区

网站首页 > 博客文章 正文

SpringBoot Controller接口参数解析转换处理

baijin 2024-08-20 10:13:57 博客文章 7 ℃ 0 评论

环境:Springboot2.4.12


1 SpringMVC流程处理核心

SpringMVC核心处理过程

  1. 查找HandlerMapping
  2. 查找HandlerAdapter
    执行HandlerInterceptor#preHandle方法
  3. 执行实际调用HandlerAdapter#handle
    通常这里执行的是RequestMappingHandlerAdapter#handle方法
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
  throws Exception {
  return handleInternal(request, response, (HandlerMethod) handler);
}

RequestMappingHandlerAdatper重写了handlerInternal方法

public class RequestMappingHandlerAdapter {
  protected ModelAndView handleInternal(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    mav = invokeHandlerMethod(request, response, handlerMethod);
  }
  protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {
      // 2.1
      WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
      // 2.2
      ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
      // 2.3
      ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
      // 将参数解析器设置到invocableMethod中
      /**
         * ProxyingHandlerMethodArgumentResolver
         * RequestParamMethodArgumentResolver
         * RequestParamMapMethodArgumentResolver
         * PathVariableMethodArgumentResolver
         * PathVariableMapMethodArgumentResolver
         * MatrixVariableMethodArgumentResolver
         * MatrixVariableMapMethodArgumentResolver
         * ServletModelAttributeMethodProcessor
         * RequestResponseBodyMethodProcessor
         * RequestPartMethodArgumentResolver
         * RequestHeaderMethodArgumentResolver
         * RequestHeaderMapMethodArgumentResolver
         * ServletCookieValueMethodArgumentResolver
         * ExpressionValueMethodArgumentResolver
         * SessionAttributeMethodArgumentResolver
         * RequestAttributeMethodArgumentResolver
         * ServletRequestMethodArgumentResolver
         * ServletResponseMethodArgumentResolver
         * HttpEntityMethodProcessor
         * RedirectAttributesMethodArgumentResolver
         * ModelMethodProcessor
         * MapMethodProcessor
         * ErrorsMethodArgumentResolver
         * SessionStatusMethodArgumentResolver
         * UriComponentsBuilderMethodArgumentResolver
         * SortHandlerMethodArgumentResolver
         * PageableHandlerMethodArgumentResolver
         * PrincipalMethodArgumentResolver
         */
      if (this.argumentResolvers != null) {
        invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
      }
      // 将返回值处理句柄设置到invocableMethod中
      /**
         * ModelAndViewMethodReturnValueHandler
         * ModelMethodProcessor
         * ViewMethodReturnValueHandler
         * ResponseBodyEmitterReturnValueHandler
         * StreamingResponseBodyReturnValueHandler
         * HttpEntityMethodProcessor
         * HttpHeadersReturnValueHandler
         * CallableMethodReturnValueHandler
         * DeferredResultMethodReturnValueHandler
         * AsyncTaskMethodReturnValueHandler
         * ServletModelAttributeMethodProcessor
         * RequestResponseBodyMethodProcessor
         * ViewNameMethodReturnValueHandler
         * MapMethodProcessor
         * ServletModelAttributeMethodProcessor
         */
      if (this.returnValueHandlers != null) {
        invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
      }
      // 将数据绑定工厂设置到InvocationHandler中
      invocableMethod.setDataBinderFactory(binderFactory);
      // 将参数名解析器设置其中,这里使用的ASM ClassReader
      invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

      ModelAndViewContainer mavContainer = new ModelAndViewContainer();
      mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
      modelFactory.initModel(webRequest, mavContainer, invocableMethod);
      mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
      // 执行实际的调用
      // 2.4 
      invocableMethod.invokeAndHandle(webRequest, mavContainer);
      return getModelAndView(mavContainer, modelFactory, webRequest);
    }
  }
}

2 执行参数绑定

2.1 创建DataBinder工厂

主要就是用来处理@InitBinder注解。包含Controller中定义局部及@ControllerAdvice全局中定义的

RequestMappingHandlerAdapter

// 过滤判断方法是否有@InitBinder注解
public static final MethodFilter INIT_BINDER_METHODS = method ->
            AnnotatedElementUtils.hasAnnotation(method, InitBinder.class);
// 全局@ControllerAdvice所在类中定义的带有@InitBinder注解的方法
private final Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache = new LinkedHashMap<>();
private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
    // 获取当前的Controller类型
    Class<?> handlerType = handlerMethod.getBeanType();
    // 从缓存中获取当前的这个Controller是否之前有做个解析当前的Controller
    // 中定义的有@InitBinder注解注释的方法
    Set<Method> methods = this.initBinderCache.get(handlerType);
    if (methods == null) {
        // 查找当前的这个Controller中所有方法上有@InitBinder注解的方法
        methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
        // 将其缓存,使用当前的Controller class对象作为key
        this.initBinderCache.put(handlerType, methods);
    }
    List<InvocableHandlerMethod> initBinderMethods = new ArrayList<>();
    // Global methods first
    // 从全局中查找
    // 这个全局是指的带有@ControllerAdivce注解的类
    // 这个的全局查找过程在什么时候执行的呢?
    // RequestMappingHandlerAdatper类实现了InitializingBean
    // 所有在afterPropertiesSet中处理查找当前容器中的所有带有@ControllerAdvice
    // 注解的类,然后将其类封装成ControllerAdviceBean对象
    // 这里就是遍历所有的ControllerAdviceBean
    // 执行ControllerAdviceBean#isApplicableToBeanType方法
    // 该方法主要就是判断当前的Controller是否在@ControllerAdvice配置的packages范围内
    // 简单说就是判断当前的Controller是否符合@ControllerAdvice配置的属性范围
    this.initBinderAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
        if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
            Object bean = controllerAdviceBean.resolveBean();
            for (Method method : methodSet) {
                // createInitBinderMethod创建InvocableHandlerMethod对象
                initBinderMethods.add(createInitBinderMethod(bean, method));
            }
        }
    });
    for (Method method : methods) {
        Object bean = handlerMethod.getBean();
        initBinderMethods.add(createInitBinderMethod(bean, method));
    }
    // 创建数据绑定工厂
    return createDataBinderFactory(initBinderMethods);
}
private InvocableHandlerMethod createInitBinderMethod(Object bean, Method method) {
    InvocableHandlerMethod binderMethod = new InvocableHandlerMethod(bean, method);
    if (this.initBinderArgumentResolvers != null) {
        // 设置参数解析器
        // 参数解析器如下:
        /**
         * RequestParamMethodArgumentResolver
         * RequestParamMapMethodArgumentResolver 
         * PathVariableMethodArgumentResolver
         * PathVariableMapMethodArgumentResolver
         * MatrixVariableMethodArgumentResolver
         * MatrixVariableMapMethodArgumentResolver
         * ExpressionValueMethodArgumentResolver
         * SessionAttributeMethodArgumentResolver 
         * RequestAttributeMethodArgumentResolver
         * ServletRequestMethodArgumentResolver
         * ServletResponseMethodArgumentResolver
         * SortHandlerMethodArgumentResolver
         * PageableHandlerMethodArgumentResolver
         * ProxyingHandlerMethodArgumentResolver
         * PrincipalMethodArgumentResolver
         * RequestParamMethodArgumentResolver
         */
        binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers);
    }
    // 设置数据绑定的工厂
    binderMethod.setDataBinderFactory(new DefaultDataBinderFactory(this.webBindingInitializer));
    // 参数名的解析,这个是通过ASM来做的 ClassReader类读取字节码文件进行解析
    binderMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
    return binderMethod;
}
protected InitBinderDataBinderFactory createDataBinderFactory(List<InvocableHandlerMethod> binderMethods)
            throws Exception {
    // WebBindingInitializer作用就是设置了类型转换器
    return new ServletRequestDataBinderFactory(binderMethods, getWebBindingInitializer());
}

2.2 创建ModelFactory

主要用来处理@ModelAttribute。包含Controller中定义局部及@ControllerAdvice全局中定义的。

RequestMappingHandlerAdapter

private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
    // 从缓存中获取SessionAttributesHandler对象
    SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
    Class<?> handlerType = handlerMethod.getBeanType();
    Set<Method> methods = this.modelAttributeCache.get(handlerType);
    if (methods == null) {
        // 从当前的缓存中查找,如果没有遍历当前Controller中的所有方法,查找方法上带有
        // @ModelAttribute注解的方法。
        methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
        this.modelAttributeCache.put(handlerType, methods);
    }
    List<InvocableHandlerMethod> attrMethods = new ArrayList<>();
    // Global methods first
    this.modelAttributeAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
        if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
            Object bean = controllerAdviceBean.resolveBean();
            for (Method method : methodSet) {
                attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
            }
        }
    });
    for (Method method : methods) {
        Object bean = handlerMethod.getBean();
        attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
    }
    return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
}
private SessionAttributesHandler getSessionAttributesHandler(HandlerMethod handlerMethod) {
    // computeIfAbsent方法会判断当前是否存在指定key的信息
    // key = 当前Controller的Class对象,value = SessionAttributesHandler
    // 这里的第二个参数是Function对象,入参是当前Controller的Class对象(type)
    return this.sessionAttributesHandlerCache.computeIfAbsent(
        handlerMethod.getBeanType(),
        type -> new SessionAttributesHandler(type, this.sessionAttributeStore));
}
private InvocableHandlerMethod createModelAttributeMethod(WebDataBinderFactory factory, Object bean, Method method) {
    InvocableHandlerMethod attrMethod = new InvocableHandlerMethod(bean, method);
    if (this.argumentResolvers != null) {
        attrMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
    }
    attrMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
    attrMethod.setDataBinderFactory(factory);
    return attrMethod;
}

2.3 创建InvocableHandlerMethod

通过当前的HandlerMethod创建InvocableHandlerMethod对象。

RequestMappingHandlerAdapter

protected ServletInvocableHandlerMethod createInvocableHandlerMethod(HandlerMethod handlerMethod) {
    return new ServletInvocableHandlerMethod(handlerMethod);
}

2.4 参数解析及绑定

开始执行数据的绑定

public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
    // providedArgs = []
    public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
        // 执行父类方法
        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        setResponseStatus(webRequest);
        try {
            this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        }
    }
}

InvocableHandlerMethod

public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
    // 从当前的请求Request中获取方法参数值信息
    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
    return doInvoke(args);
}
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
    // 获取当前Controller请求的接口的方法参数信息,每一个参数对应一个MethodParameter对象
    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;
        }
        // 这里会依次遍历所有的参数解析器,查找出能够处理当前请求方法中该参数的解析器
        // 如:query(String id) 这样的就会返回RequestParamMethodArgumentResolver解析器
        // 同时会吧找出来的该解析器与当前请求方法的请求参数进行绑定缓存
        if (!this.resolvers.supportsParameter(parameter)) {
            throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
        }
        try {
            // 执行参数的解析及参数的绑定
            // 这里的this.dataBinderFactory就是上面2.1中创建的数据绑定工厂
            args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
        }
    }
    return args;
}

HandlerMethodArgumentResolverComposite

public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {

    private final List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>();

    private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache =
            new ConcurrentHashMap<>(256);
    public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
        // 获取在上一步中找到的参数解析器
        HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
        // 解析参数
        return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
    }
    
}

这里我们都是以query(String id)这样的请求接口进行解读源码。那这里进入到RequestParamMethodArgumentResolver中进行参数的继续及数据绑定。这里调用父类方法

public abstract class AbstractNamedValueMethodArgumentResolver {
    public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

        // 返回RequestParamNamedValueInfo
		NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
		MethodParameter nestedParameter = parameter.nestedIfOptional();

        // 这里就返回了参数的名称如:id, idNo也就是你接口参数的名称
		Object resolvedName = resolveEmbeddedValuesAndExpressions(namedValueInfo.name);
        // 这里就根据参数的名称从HttpServletRequet对象中获取值
        // 2.4.1 
        // 加入接口query(String id)
		Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
		if (arg == null) {
			if (namedValueInfo.defaultValue != null) {
				arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
			} else if (namedValueInfo.required && !nestedParameter.isOptional()) {
				handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
			}
			arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
		} else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
			arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
		}
		// 进行参数绑定
		if (binderFactory != null) {
            // 通过工厂创建数据绑定对象
            // 2.4.2
			WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
			try {
                // 通过数据绑定对象进行类型的转换
                // 2.4.3 
                // parameter.getParameterType()获取当前参数的Class类型
				arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
			}
			// Check for null value after conversion of incoming argument value
			if (arg == null && namedValueInfo.defaultValue == null &&
					namedValueInfo.required && !nestedParameter.isOptional()) {
				handleMissingValueAfterConversion(namedValueInfo.name, nestedParameter, webRequest);
			}
		}

		handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);

		return arg;
	}
}

2.4.1 获取参数值

public class RequestParamMethodArgumentResolver {
    protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
		HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);

		if (servletRequest != null) {
			Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest);
			if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) {
				return mpArg;
			}
		}

		Object arg = null;
		MultipartRequest multipartRequest = request.getNativeRequest(MultipartRequest.class);
		if (multipartRequest != null) {
			List<MultipartFile> files = multipartRequest.getFiles(name);
			if (!files.isEmpty()) {
				arg = (files.size() == 1 ? files.get(0) : files);
			}
		}
		if (arg == null) {
            // 一般参数类型都在此处获取
			String[] paramValues = request.getParameterValues(name);
			if (paramValues != null) {
				arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
			}
		}
		return arg;
	}
}

2.4.2 创建数据绑定对象

通过上面知道数据绑定工厂是ServletRequestDataBinderFactory对象,这里调用父类的方法

public class DefaultDataBinderFactory implements WebDataBinderFactory {
    public final WebDataBinder createBinder(
			NativeWebRequest webRequest, @Nullable Object target, String objectName) throws Exception {
        // createBinderInstance在ServletRequestDataBinderFactory中
		WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest);
        // initializer = ConfigurableWebBindingInitializer
        // 在构造数据绑定工厂的时候在构造函数中传入的
		if (this.initializer != null) {
            // 2.4.2.1
			this.initializer.initBinder(dataBinder, webRequest);
		}
        // 初始化绑定方法的执行也就是Controller中
        // 或者@ControllerAdvice中定义的@InitBinder注解方法
        // 	这里执行子类InitBinderDataBinderFactory方法
		initBinder(dataBinder, webRequest);
		return dataBinder;
	}
}
public class InitBinderDataBinderFactory extends DefaultDataBinderFactory {
    public void initBinder(WebDataBinder dataBinder, NativeWebRequest request) throws Exception {
		for (InvocableHandlerMethod binderMethod : this.binderMethods) {
			if (isBinderMethodApplicable(binderMethod, dataBinder)) {
				Object returnValue = binderMethod.invokeForRequest(request, null, dataBinder);
			}
		}
	}
    protected boolean isBinderMethodApplicable(HandlerMethod initBinderMethod, WebDataBinder dataBinder) {
        // 获取方法上是否有@InitBinder注解
		InitBinder ann = initBinderMethod.getMethodAnnotation(InitBinder.class);
        // 没有直接抛出异常
		Assert.state(ann != null, "No InitBinder annotation");
        // 注解中是否定义了属性信息,可以针对对象的某些属性进行处理
		String[] names = ann.value();
		return (ObjectUtils.isEmpty(names) || ObjectUtils.containsElement(names, dataBinder.getObjectName()));
	}
}

ServletRequestDataBinderFactory

public class ServletRequestDataBinderFactory extends InitBinderDataBinderFactory {
	@Override
	protected ServletRequestDataBinder createBinderInstance(
			@Nullable Object target, String objectName, NativeWebRequest request) throws Exception  {
        // target = null
        // objectName = id
		return new ExtendedServletRequestDataBinder(target, objectName);
	}

}

2.4.2.1 绑定初始化

public interface WebBindingInitializer {
    default void initBinder(WebDataBinder binder, WebRequest request) {
		initBinder(binder);
	}
}
// 关于该对象的默认配置
// 查看源码WebMvcConfigurationSupport#requestMappingHandlerAdapter方法
public class ConfigurableWebBindingInitializer implements WebBindingInitializer {
    public void initBinder(WebDataBinder binder) {
		binder.setAutoGrowNestedPaths(this.autoGrowNestedPaths);
        // 下面相应的参数都可以在构建ConfigurableWebBindingInitializer
        // 时候设置
        // 比如directFieldAccess属性设置为true后,就可以直接通过属性注入无需setter
		if (this.directFieldAccess) {
			binder.initDirectFieldAccess();
		}
		if (this.messageCodesResolver != null) {
			binder.setMessageCodesResolver(this.messageCodesResolver);
		}
		if (this.bindingErrorProcessor != null) {
			binder.setBindingErrorProcessor(this.bindingErrorProcessor);
		}
		if (this.validator != null && binder.getTarget() != null &&
				this.validator.supports(binder.getTarget().getClass())) {
			binder.setValidator(this.validator);
		}
		if (this.conversionService != null) {
            // 设置转换服务,比如String到Integer的转换,系统提供了很多默认的转换服务
			binder.setConversionService(this.conversionService);
		}
		if (this.propertyEditorRegistrars != null) {
			for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) {
				propertyEditorRegistrar.registerCustomEditors(binder);
			}
		}
	}
}

2.4.3 参数类型转换

当前数据绑定对象是ExtendedServletRequestDataBinder

调用父类DataBinder方法

public class DataBinder implements PropertyEditorRegistry, TypeConverter {
    public <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType,
			@Nullable MethodParameter methodParam) throws TypeMismatchException {
        // getTypeConverter返回SimpleTypeConverter
        // convertIfNecessary方法执行SimpleTypeConverter的父类TypeConverterSupport方法
		return getTypeConverter().convertIfNecessary(value, requiredType, methodParam);
	}
    protected TypeConverter getTypeConverter() {
		if (getTarget() != null) {
			return getInternalBindingResult().getPropertyAccessor();
		} else {
            // 执行这里
			return getSimpleTypeConverter();
		}
	}
    protected SimpleTypeConverter getSimpleTypeConverter() {
		if (this.typeConverter == null) {
            // 创建
			this.typeConverter = new SimpleTypeConverter();
			if (this.conversionService != null) {
                // 将类型转换器设置其中
				this.typeConverter.setConversionService(this.conversionService);
			}
		}
		return this.typeConverter;
	}
}
public abstract class TypeConverterSupport extends PropertyEditorRegistrySupport implements TypeConverter {
  // value,requiredType都已经是确定的信息就是进行转换了
  public <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, 
                                  @Nullable MethodParameter methodParam) throws TypeMismatchException {
    // 这里的转换会先从自定义的转换器中找,如果没有再从默认中查找
    return convertIfNecessary(value, requiredType, (methodParam != null ? new TypeDescriptor(methodParam) : TypeDescriptor.valueOf(requiredType)));
  }
  public <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable TypeDescriptor typeDescriptor) throws TypeMismatchException {
    try {
      return this.typeConverterDelegate.convertIfNecessary(null, null, value, requiredType, typeDescriptor);
    }
  }
}

TypeConverterDelegate

class TypeConverterDelegate {
  public <T> T convertIfNecessary(@Nullable String propertyName, @Nullable Object oldValue, @Nullable Object newValue, 
                                  @Nullable Class<T> requiredType, @Nullable TypeDescriptor typeDescriptor) throws IllegalArgumentException {
    // Custom editor for this type?
    // 先从自定义中查找哦
    // 这里的propertyEditorRegistry对象就是SimpleTypeConverter
    // 这个在创建SimpleTypeConverter时候就指定了
    // findCustomEditor方法就是从customEditorsForPath集合中查找,看如下的示例
    PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
    // ...
    return (T) convertedValue;
  }
}

通过如下可以看到自定义的数据绑定是怎么注册的

@InitBinder("idNo")
public void binder(WebDataBinder binder) {
  binder.registerCustomEditor(String.class, new PropertyEditorSupport() {
    @Override
    public String getAsText() {
      return super.getAsText() ;
    }
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
      setValue("Customer-" + text) ;
    }
  });
}

DateBinder

public void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor) {
    getPropertyEditorRegistry().registerCustomEditor(requiredType, propertyEditor);
}
protected PropertyEditorRegistry getPropertyEditorRegistry() {
  if (getTarget() != null) {
    return getInternalBindingResult().getPropertyAccessor();
  } else {
    // 默认返回SimpleTypeConverter
    return getSimpleTypeConverter();
  }
}

SimpleTypeConverter继承PropertyEditorRegistrySupport

private Map<String, CustomEditorHolder> customEditorsForPath;
public void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor) {
  registerCustomEditor(requiredType, null, propertyEditor);
}

@Override
public void registerCustomEditor(@Nullable Class<?> requiredType, @Nullable String propertyPath, PropertyEditor propertyEditor) {
  if (propertyPath != null) {
    if (this.customEditorsForPath == null) {
      this.customEditorsForPath = new LinkedHashMap<>(16);
    }
    this.customEditorsForPath.put(propertyPath, new CustomEditorHolder(propertyEditor, requiredType));
  } else {
    if (this.customEditors == null) {
      this.customEditors = new LinkedHashMap<>(16);
    }
    this.customEditors.put(requiredType, propertyEditor);
    this.customEditorCache = null;
  }
}


完毕!!!

关注+转发

Spring MVC 异步请求方式
spring data jpa 高级应用
Spring Retry重试框架的应用
Spring容器这些扩展点你都清楚了吗?
Spring事务实现原理源码分析
Spring MVC 异常处理方式
SpringBoot WebFlux整合Spring Security进行权限认证
Spring 自定义Advisor以编程的方式实现AOP
Spring Cloud Sentinel 流控限流
Spring Cloud Gateway应用详解1之谓词
Spring AOP切入点类型及系统提供的非常常用的切入点
Spring中Aware接口实现原理解析
Spring AOP实现原理源码详细分析

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表