springmvc源码解析之@EnableWebMvc四

说在前面

本次主要介绍springmvc配置解析。关注“天河聊架构”微信公众号有更多精彩。

 

springmvc配置解析

@EnableWebMvc这个注解干了什么,初始化RequestMappingHandlerAdapter

进入到这个方法org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#requestMappingHandlerAdapter

@Bean
   public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
//    创建requestMappingHandlerAdapter -》
      RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
//    设置媒体类型管理器 -》
      adapter.setContentNegotiationManager(mvcContentNegotiationManager());
//    添加消息转换器 -》
      adapter.setMessageConverters(getMessageConverters());
//    设置配置绑定器 -》
      adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
//    设置参数解析器 -》
      adapter.setCustomArgumentResolvers(getArgumentResolvers());
//    设置returnHandlers
      adapter.setCustomReturnValueHandlers(getReturnValueHandlers());
      if (jackson2Present) {
//       设置JsonViewRequestBodyAdvice、JsonViewResponseBodyAdvice
         adapter.setRequestBodyAdvice(
               Collections.<RequestBodyAdvice>singletonList(new JsonViewRequestBodyAdvice()));
         adapter.setResponseBodyAdvice(
               Collections.<ResponseBodyAdvice<?>>singletonList(new JsonViewResponseBodyAdvice()));
      }

//    创建异步支持配置器
      AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
//    配置异步支持配置器
      configureAsyncSupport(configurer);
      if (configurer.getTaskExecutor() != null) {
//       设置任务执行器
         adapter.setTaskExecutor(configurer.getTaskExecutor());
      }
      if (configurer.getTimeout() != null) {
//       设置超时时间
         adapter.setAsyncRequestTimeout(configurer.getTimeout());
      }
//    设置返回值拦截器
      adapter.setCallableInterceptors(configurer.getCallableInterceptors());
//    设置延迟结果拦截器
      adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());
      return adapter;
   }

进入到这个方法org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#RequestMappingHandlerAdapter

public RequestMappingHandlerAdapter() {
//    创建StringHttpMessageConverter
      StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
      stringHttpMessageConverter.setWriteAcceptCharset(false);  // see SPR-7316
//    添加转换器
      this.messageConverters = new ArrayList<HttpMessageConverter<?>>(4);
      this.messageConverters.add(new ByteArrayHttpMessageConverter());
      this.messageConverters.add(stringHttpMessageConverter);
      this.messageConverters.add(new SourceHttpMessageConverter<Source>());
//    添加xml和json转换器 -》
      this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
   }

进入到这个方法org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter#AllEncompassingFormHttpMessageConverter

public AllEncompassingFormHttpMessageConverter() {
//    添加默认xml和json真支持转换器
      addPartConverter(new SourceHttpMessageConverter<Source>());
      if (jaxb2Present && !jackson2XmlPresent) {
         addPartConverter(new Jaxb2RootElementHttpMessageConverter());
      }

      if (jackson2Present) {
         addPartConverter(new MappingJackson2HttpMessageConverter());
      }
      else if (gsonPresent) {
         addPartConverter(new GsonHttpMessageConverter());
      }

      if (jackson2XmlPresent) {
         addPartConverter(new MappingJackson2XmlHttpMessageConverter());
      }
   }

往上返回到这个方法org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#mvcContentNegotiationManager

@Bean
   public ContentNegotiationManager mvcContentNegotiationManager() {
      if (this.contentNegotiationManager == null) {
//       初始化媒体类型管理器
         ContentNegotiationConfigurer configurer = new ContentNegotiationConfigurer(this.servletContext);
//       设置默认类型 -》
         configurer.mediaTypes(getDefaultMediaTypes());
//       配置媒体类型管理器 -》
         configureContentNegotiation(configurer);
//       构建媒体类型管理器 -》
         this.contentNegotiationManager = configurer.buildContentNegotiationManager();
      }
      return this.contentNegotiationManager;
   }

进入到这个方法org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#getDefaultMediaTypes

protected Map<String, MediaType> getDefaultMediaTypes() {
   Map<String, MediaType> map = new HashMap<String, MediaType>(4);
   if (romePresent) {
      map.put("atom", MediaType.APPLICATION_ATOM_XML);
      map.put("rss", MediaType.APPLICATION_RSS_XML);
   }
   if (jaxb2Present || jackson2XmlPresent) {
      map.put("xml", MediaType.APPLICATION_XML);
   }
   if (jackson2Present || gsonPresent) {
      map.put("json", MediaType.APPLICATION_JSON);
   }
   return map;
}

往上返回到这个方法org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration#configureContentNegotiation

@Override
protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
   this.configurers.configureContentNegotiation(configurer);
}

往上返回到这个方法org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer#buildContentNegotiationManager

protected ContentNegotiationManager buildContentNegotiationManager() {
//    添加媒体类型
      this.factory.addMediaTypes(this.mediaTypes);
//    等待ContentNegotiationManagerFactoryBean初始化配置
      this.factory.afterPropertiesSet();
      return this.factory.getObject();
   }

往上返回到这个方法org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#getMessageConverters

protected final List<HttpMessageConverter<?>> getMessageConverters() {
      if (this.messageConverters == null) {
         this.messageConverters = new ArrayList<HttpMessageConverter<?>>();
//       配置消息转换器 -》
         configureMessageConverters(this.messageConverters);
         if (this.messageConverters.isEmpty()) {
//          添加默认http消息转换器 -》
            addDefaultHttpMessageConverters(this.messageConverters);
         }
//       扩展消息转换器
         extendMessageConverters(this.messageConverters);
      }
      return this.messageConverters;
   }

进入到这个方法org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration#configureMessageConverters

@Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
   this.configurers.configureMessageConverters(converters);
}

往上返回到这个方法org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#addDefaultHttpMessageConverters

protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
//    创建StringHttpMessageConverter
      StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
      stringConverter.setWriteAcceptCharset(false);
      messageConverters.add(new ByteArrayHttpMessageConverter());
      messageConverters.add(stringConverter);
      messageConverters.add(new ResourceHttpMessageConverter());
      messageConverters.add(new SourceHttpMessageConverter<Source>());
//    -》
      messageConverters.add(new AllEncompassingFormHttpMessageConverter());
      if (romePresent) {
         messageConverters.add(new AtomFeedHttpMessageConverter());
         messageConverters.add(new RssChannelHttpMessageConverter());
      }

//    Jackson2Xml 转换器
      if (jackson2XmlPresent) {
         messageConverters.add(new MappingJackson2XmlHttpMessageConverter(
               Jackson2ObjectMapperBuilder.xml().applicationContext(this.applicationContext).build()));
      }
      else if (jaxb2Present) {
//       Jaxb2RootElement 转换器
         messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
      }

//    Jackson 转换器
      if (jackson2Present) {
         messageConverters.add(new MappingJackson2HttpMessageConverter(
               Jackson2ObjectMapperBuilder.json().applicationContext(this.applicationContext).build()));
      }
      else if (gsonPresent) {
//       gson 转换器
         messageConverters.add(new GsonHttpMessageConverter());
      }
   }

进入到这个方法org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter#AllEncompassingFormHttpMessageConverter

public AllEncompassingFormHttpMessageConverter() {
//    添加默认xml和json真支持转换器
      addPartConverter(new SourceHttpMessageConverter<Source>());
      if (jaxb2Present && !jackson2XmlPresent) {
         addPartConverter(new Jaxb2RootElementHttpMessageConverter());
      }

      if (jackson2Present) {
         addPartConverter(new MappingJackson2HttpMessageConverter());
      }
      else if (gsonPresent) {
         addPartConverter(new GsonHttpMessageConverter());
      }

      if (jackson2XmlPresent) {
         addPartConverter(new MappingJackson2XmlHttpMessageConverter());
      }
   }

往上返回到这个方法org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#getConfigurableWebBindingInitializer

protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
//    初始化配置绑定器
      ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
//    设置转换服务 -》
      initializer.setConversionService(mvcConversionService());
//    设置校验器-》
      initializer.setValidator(mvcValidator());
//    设置MessageCodesResolver
      initializer.setMessageCodesResolver(getMessageCodesResolver());
      return initializer;
   }

进入到这个方法org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#mvcConversionService

@Bean
   public FormattingConversionService mvcConversionService() {
//    初始化默认转换服务
      FormattingConversionService conversionService = new DefaultFormattingConversionService();
//    添加格式化器 -》
      addFormatters(conversionService);
      return conversionService;
   }

这里前面介绍过了。

往上返回到这个方法org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#mvcValidator

@Bean
   public Validator mvcValidator() {
//    获取验证器
      Validator validator = getValidator();
      if (validator == null) {
         if (ClassUtils.isPresent("javax.validation.Validator", getClass().getClassLoader())) {
            Class<?> clazz;
            try {
               String className = "org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean";
               clazz = ClassUtils.forName(className, WebMvcConfigurationSupport.class.getClassLoader());
            }
            catch (ClassNotFoundException ex) {
               throw new BeanInitializationException("Could not find default validator class", ex);
            }
            catch (LinkageError ex) {
               throw new BeanInitializationException("Could not load default validator class", ex);
            }
            validator = (Validator) BeanUtils.instantiateClass(clazz);
         }
         else {
            validator = new NoOpValidator();
         }
      }
      return validator;
   }

往上返回到这个方法org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#getArgumentResolvers

protected final List<HandlerMethodArgumentResolver> getArgumentResolvers() {
   if (this.argumentResolvers == null) {
      this.argumentResolvers = new ArrayList<HandlerMethodArgumentResolver>();
      addArgumentResolvers(this.argumentResolvers);
   }
   return this.argumentResolvers;
}

进入到这个方法org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration#addArgumentResolvers

@Override
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
   this.configurers.addArgumentResolvers(argumentResolvers);
}

往上返回到这个方法org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#getReturnValueHandlers

protected final List<HandlerMethodReturnValueHandler> getReturnValueHandlers() {
   if (this.returnValueHandlers == null) {
      this.returnValueHandlers = new ArrayList<HandlerMethodReturnValueHandler>();
      addReturnValueHandlers(this.returnValueHandlers);
   }
   return this.returnValueHandlers;
}

进入到这个方法org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration#addReturnValueHandlers

@Override
protected void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
   this.configurers.addReturnValueHandlers(returnValueHandlers);
}

往上返回到这个方法org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#requestMappingHandlerAdapter

进入到这个方法org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#afterPropertiesSet

@Override
   public void afterPropertiesSet() {
      // Do this first, it may add ResponseBody advice beans 初始化ControllerAdvice缓存-》
      initControllerAdviceCache();
      if (this.argumentResolvers == null) {
//       获取默认的方法参数解析器 -》
         List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
         this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
      }
      if (this.initBinderArgumentResolvers == null) {
//       获取默认的@InitBinder参数绑定解析器 -》
         List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
         this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
      }
      if (this.returnValueHandlers == null) {
//       解析默认的返回值handler -》
         List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
         this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
      }
   }

往上返回到这个方法org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#initControllerAdviceCache

private void initControllerAdviceCache() {
      if (getApplicationContext() == null) {
         return;
      }
      if (logger.isInfoEnabled()) {
         logger.info("Looking for @ControllerAdvice: " + getApplicationContext());
      }
//    从beanFactory中获取参数@ControllerAdvice的controller
      List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
      AnnotationAwareOrderComparator.sort(beans);
      List<Object> requestResponseBodyAdviceBeans = new ArrayList<Object>();
      for (ControllerAdviceBean bean : beans) {
//       从controller中获取有@RequestMapping、@ModelAttribute注解的方法
         Set<Method> attrMethods = MethodIntrospector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
         if (!attrMethods.isEmpty()) {
            this.modelAttributeAdviceCache.put(bean, attrMethods);
            if (logger.isInfoEnabled()) {
               logger.info("Detected @ModelAttribute methods in " + bean);
            }
         }
//       查找controller中有@InitBinder注解的方法
         Set<Method> binderMethods = MethodIntrospector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);
         if (!binderMethods.isEmpty()) {
            this.initBinderAdviceCache.put(bean, binderMethods);
            if (logger.isInfoEnabled()) {
               logger.info("Detected @InitBinder methods in " + bean);
            }
         }
         if (RequestBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
            requestResponseBodyAdviceBeans.add(bean);
            if (logger.isInfoEnabled()) {
               logger.info("Detected RequestBodyAdvice bean in " + bean);
            }
         }
         if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
            requestResponseBodyAdviceBeans.add(bean);
            if (logger.isInfoEnabled()) {
               logger.info("Detected ResponseBodyAdvice bean in " + bean);
            }
         }
      }

      if (!requestResponseBodyAdviceBeans.isEmpty()) {
         this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
      }
   }

往上返回到这个方法org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getDefaultArgumentResolvers

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
      List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
      // Annotation-based argument resolution
//    基于@RequestParam的参数解析器
      resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
//    基于@RequestParam map参数解析器
      resolvers.add(new RequestParamMapMethodArgumentResolver());
//    基于@PathVariable的参数解析器
      resolvers.add(new PathVariableMethodArgumentResolver());
//    基于@PathVariable map的参数解析器
      resolvers.add(new PathVariableMapMethodArgumentResolver());
//    基于@MatrixVariable 矩阵参数解析器
      resolvers.add(new MatrixVariableMethodArgumentResolver());
//    基于@MatrixVariable 矩阵map参数解析器
      resolvers.add(new MatrixVariableMapMethodArgumentResolver());
//    基于从model解析参数的参数解析器
      resolvers.add(new ServletModelAttributeMethodProcessor(false));
//    基于@RequestBody、@ResponseBody的参数解析器
      resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
//    基于@RequestParam 参数解析器
      resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
//    基于@RequestHeader 参数解析器
      resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
//    基于@RequestHeader map参数解析器
      resolvers.add(new RequestHeaderMapMethodArgumentResolver());
//    基于从cookie中解析参数的参数解析器
      resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
//    基于@Value 表达式参数解析器
      resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
//    基于@SessionAttribute 参数解析器
      resolvers.add(new SessionAttributeMethodArgumentResolver());
//    基于@RequestAttribute 参数解析器
      resolvers.add(new RequestAttributeMethodArgumentResolver());
      // Type-based argument resolution
//    基于servletRequest的参数解析器
      resolvers.add(new ServletRequestMethodArgumentResolver());
//    基于servletResponse的参数解析器
      resolvers.add(new ServletResponseMethodArgumentResolver());
//    基于httpEntity参数解析器
      resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
//    基于重定向参数绑定解析器
      resolvers.add(new RedirectAttributesMethodArgumentResolver());
//    基于从model中解析参数的参数解析器
      resolvers.add(new ModelMethodProcessor());
//    基于map的参数解析器
      resolvers.add(new MapMethodProcessor());
//    错误方法参数解析器
      resolvers.add(new ErrorsMethodArgumentResolver());
//    基于session状态方法参数解析器
      resolvers.add(new SessionStatusMethodArgumentResolver());
//    基于url参数解析器
      resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
      // Custom arguments 自定义参数解析器
      if (getCustomArgumentResolvers() != null) {
         resolvers.addAll(getCustomArgumentResolvers());
      }

      // Catch-all
//     基于@RequestParam参数解析器,用默认值
      resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
//    基于servlet model中解析参数的参数解析器,使用默认值
      resolvers.add(new ServletModelAttributeMethodProcessor(true));
      return resolvers;
   }

往上返回到这个方法org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getDefaultInitBinderArgumentResolvers

private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {
      List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
      // Annotation-based argument resolution
//    基于@RequestParam的参数解析器
      resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
//    基于@RequestParam map的参数解析器
      resolvers.add(new RequestParamMapMethodArgumentResolver());
//    基于@PathVariable 的参数解析器
      resolvers.add(new PathVariableMethodArgumentResolver());
//    基于@PathVariable map的参数解析器
      resolvers.add(new PathVariableMapMethodArgumentResolver());
//    基于@MatrixVariable 矩阵参数解析器
      resolvers.add(new MatrixVariableMethodArgumentResolver());
//    基于@MatrixVariable map矩阵参数解析器
      resolvers.add(new MatrixVariableMapMethodArgumentResolver());
//    基于@Value 表达式参数解析器
      resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
//    基于@SessionAttribute参数解析器
      resolvers.add(new SessionAttributeMethodArgumentResolver());
//    基于@RequestAttribute 参数解析器
      resolvers.add(new RequestAttributeMethodArgumentResolver());
      // Type-based argument resolution
//    基于servletRequest参数解析器
      resolvers.add(new ServletRequestMethodArgumentResolver());
//    基于servletResponse参数解析器
      resolvers.add(new ServletResponseMethodArgumentResolver());
      // Custom arguments
      if (getCustomArgumentResolvers() != null) {
         resolvers.addAll(getCustomArgumentResolvers());
      }

      // Catch-all
//    基于@RequestParam 参数解析器,使用默认值
      resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
      return resolvers;
   }

往上返回到这个方法org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getDefaultReturnValueHandlers

private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
      List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();
      // Single-purpose return value types
//    方法返回值是ModelAndView的返回值解析器
      handlers.add(new ModelAndViewMethodReturnValueHandler());
//    方法返回值是model的返回值解析器
      handlers.add(new ModelMethodProcessor());
//    方法是返回值是view的返回值解析器
      handlers.add(new ViewMethodReturnValueHandler());
//    方法返回值是responseEntity的返回值解析器
      handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters()));
//    方法返回值是流的返回值解析器
      handlers.add(new StreamingResponseBodyReturnValueHandler());
//    方法返回值是httpEntity的方法返回值解析器
      handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
            this.contentNegotiationManager, this.requestResponseBodyAdvice));
//    方法返回值是httpHeaders的方法返回值解析器
      handlers.add(new HttpHeadersReturnValueHandler());
//    方法返回值是callable的方法返回值解析器
      handlers.add(new CallableMethodReturnValueHandler());
//    方法返回值是DeferredResult的方法返回值解析器
      handlers.add(new DeferredResultMethodReturnValueHandler());
//    方法返回值是WebAsyncTask的方法返回值解析器
      handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
      // Annotation-based return value types
//    方法上有@ModelAttribute注解的返回值解析器
      handlers.add(new ModelAttributeMethodProcessor(false));
//    基于@RequestBody、@ResponseBody的返回值解析器
      handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
            this.contentNegotiationManager, this.requestResponseBodyAdvice));
      // Multi-purpose return value types
//    基于视图名字的返回值解析器
      handlers.add(new ViewNameMethodReturnValueHandler());
//    基于map的返回值解析器
      handlers.add(new MapMethodProcessor());
      // Custom return value types 自定义返回值解析器
      if (getCustomReturnValueHandlers() != null) {
         handlers.addAll(getCustomReturnValueHandlers());
      }

      // Catch-all
//    基于modelAndView的返回值解析器
      if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
         handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
      }
      else {
//       方法上有@ModelAttribute注解的返回值解析器,使用默认值
         handlers.add(new ModelAttributeMethodProcessor(true));
      }

      return handlers;
   }

往上返回到这个方法org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#afterPropertiesSet

 

说到最后

本次源码解析仅代表个人观点,仅供参考。

 

转载于:https://my.oschina.net/u/3775437/blog/3025494

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值