zoukankan      html  css  js  c++  java
  • spring mvc中的控制器方法中的参数从哪里传进来?

    编写控制器方法的时候很奇怪,spring是怎么知道你控制器方法的参数类型,并且注入正确的对象呢?

    比如下面这样

    @RequestMapping(value="/register", method=GET)
      public String showRegistrationForm(Model model) {
        model.addAttribute(new Spitter());
        return "registerForm";
      }

    他怎么知道Model对应啥呢?

    其实,spring首先会反射这个方法,然后获得参数的类型,另外在spring中,保存着一系列的argumentResolvers参数理器对象,这些参数处理器都是不同的HandlerMethodArgumentResolver类的不同子类的实例。然后用循环,一个个测试这些参数处理器是否支持这个参数的类型,如果支持,就返回这个参数处理器,并用这个参数处理器的resolveArgument方法,该方法会返回一个合适的参数对象,这个参数对象是我们写的控制方法参数的子类。比如上面showRegistrationForm(Model model)的参数对象是Model,那么支持Model参数的参数处理器就是ModelAndViewContainer类的对象,然后然后这个参数处理器对象的resolveArgument方法会返回一个BindingAwareModelMap对象,这个BindingAwareModelMap对象正好是Model的子类,传入showRegistrationForm(Model model)中,我们就可以通过model操作这个对象了。

    这个循环检测是在HandlerMethodArguementResolverComposite类的getArgumentResolver方法中进行的:

    private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
            HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
            if (result == null) {
                for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" +
                                parameter.getGenericParameterType() + "]");
                    }
                    if (methodArgumentResolver.supportsParameter(parameter)) {
                        result = methodArgumentResolver;
                        this.argumentResolverCache.put(parameter, result);
                        break;
                    }
                }
            }
            return result;
        }

    另外还可以看到,这个方法中用了缓存,这样当以后再次进入这个控制器方法是,就直接从缓存中取得argumentResolver就可以了。

    如果是控制器方法的参数是一个普通的pojo(不是ioc容器中管理的spring bean),比如对应一个表单的数据,比如下面这样,应该怎么处理呢?

      @RequestMapping(value="/register", method=POST)
      public String processRegistration(
          @Valid Spitter spitter, 
          Errors errors) {
        if (errors.hasErrors()) {
          return "registerForm";
        }
        
        spitterRepository.save(spitter);
        return "redirect:/spitter/" + spitter.getUsername();
      }

    processRegistration的第一个参数是Spitter,他只是一个普通的自定义的pojo,那么这个参数将被看作是一个模型属性,并且用ModleAttributeMethodProcessor这个参数处理器来处理。ModleAttributeMethodProcessor的resolveArgument 方法如下:

     1 public final Object resolveArgument(
     2             MethodParameter parameter, ModelAndViewContainer mavContainer,
     3             NativeWebRequest request, WebDataBinderFactory binderFactory)
     4             throws Exception {
     5 
     6         String name = ModelFactory.getNameForParameter(parameter);
     7         Object attribute = (mavContainer.containsAttribute(name)) ?
     8                 mavContainer.getModel().get(name) : createAttribute(name, parameter, binderFactory, request);
     9 
    10         WebDataBinder binder = binderFactory.createBinder(request, attribute, name);
    11         if (binder.getTarget() != null) {
    12             bindRequestParameters(binder, request);
    13             validateIfApplicable(binder, parameter);
    14             if (binder.getBindingResult().hasErrors()) {
    15                 if (isBindExceptionRequired(binder, parameter)) {
    16                     throw new BindException(binder.getBindingResult());
    17                 }
    18             }
    19         }

    看山上面第8行,如果模型中没有这个属性对象,那么就会createAttribute创建这个属性,再看creat4eAttribute这个方法是怎么创建pojo对象的:

        protected Object createAttribute(String attributeName, MethodParameter parameter,
                WebDataBinderFactory binderFactory,  NativeWebRequest request) throws Exception {
    
            return BeanUtils.instantiateClass(parameter.getParameterType());
        }

    果然没错,就是用java的反射,根据对象的类型instance一个实例,最后返回,完毕。

  • 相关阅读:
    Codeforces Gym 101138 D. Strange Queries
    BZOJ 4236: JOIOJI
    BZOJ 2654: tree
    POJ 1390 Block
    2048
    BZOJ 2412: 电路检修
    BZOJ 2448: 挖油
    BZOJ 3907: 网格
    Codeforces 727 D T-shirts Distribution
    BZOJ 1485: [HNOI2009]有趣的数列
  • 原文地址:https://www.cnblogs.com/JMLiu/p/9998356.html
Copyright © 2011-2022 走看看