springmvc源碼解析之@EnableWebMvc四

說在前面java

本次主要介紹springmvc配置解析。關注「天河聊架構」微信公衆號有更多精彩。web

 

springmvc配置解析spring

@EnableWebMvc這個註解幹了什麼,初始化RequestMappingHandlerAdapterjson

進入到這個方法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#AllEncompassingFormHttpMessageConvertercookie

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#mvcContentNegotiationManagersession

@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#configureContentNegotiationmvc

@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

 

說到最後

本次源碼解析僅表明我的觀點,僅供參考。

相關文章
相關標籤/搜索