123.【SpringBoot 源码刨析B】(七)

简介: 123.【SpringBoot 源码刨析B】
(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;
  }



相关文章
|
6天前
基于springboot+thymeleaf+Redis仿知乎网站问答项目源码
基于springboot+thymeleaf+Redis仿知乎网站问答项目源码
54 36
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue实现的高校食堂移动预约点餐系统设计与实现(源码+文档+部署)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
21 3
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue实现的留守儿童爱心网站设计与实现(计算机毕设项目实战+源码+文档)
博主是一位全网粉丝超过100万的CSDN特邀作者、博客专家,专注于Java、Python、PHP等技术领域。提供SpringBoot、Vue、HTML、Uniapp、PHP、Python、NodeJS、爬虫、数据可视化等技术服务,涵盖免费选题、功能设计、开题报告、论文辅导、答辩PPT等。系统采用SpringBoot后端框架和Vue前端框架,确保高效开发与良好用户体验。所有代码由博主亲自开发,并提供全程录音录屏讲解服务,保障学习效果。欢迎点赞、收藏、关注、评论,获取更多精品案例源码。
27 10
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue实现的家政服务管理平台设计与实现(计算机毕设项目实战+源码+文档)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
20 8
|
1天前
|
JavaScript 搜索推荐 Java
基于SpringBoot+Vue实现的家乡特色推荐系统设计与实现(源码+文档+部署)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
18 8
|
1天前
|
JavaScript NoSQL Java
基于SpringBoot+Vue实现的大学生体质测试管理系统设计与实现(系统源码+文档+数据库+部署)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
16 2
|
1天前
|
JavaScript NoSQL Java
基于SpringBoot+Vue实现的大学生就业服务平台设计与实现(系统源码+文档+数据库+部署等)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
16 6
|
1天前
|
JavaScript NoSQL Java
基于SpringBoot+Vue的班级综合测评管理系统设计与实现(系统源码+文档+数据库+部署等)
✌免费选题、功能需求设计、任务书、开题报告、中期检查、程序功能实现、论文辅导、论文降重、答辩PPT辅导、会议视频一对一讲解代码等✌
20 4
|
1天前
|
JavaScript Java 测试技术
基于Java+SpringBoot+Vue实现的车辆充电桩系统设计与实现(系统源码+文档+部署讲解等)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
22 6
|
1天前
|
JavaScript NoSQL Java
基于SpringBoot+Vue实现的冬奥会科普平台设计与实现(系统源码+文档+数据库+部署)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
17 0