Spring Boot 对Spring MVC的自动配置

 

从官网API入手查看Sring Boot 为Spring MVC提供了那些配置,官方API链接如下:Spring Boot官方API

下面是对API的原文内容进行翻译说明:

Spring Boot provides auto-configuration for Spring MVC that works well with most applications.

Spring Boot 提供了Spring mvc 需要工作运行的绝大部分应用。

The auto-configuration adds the following features on top of Spring’s defaults:

  • Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
    • 自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何
      渲染(转发?重定向?))
    • ContentNegotiatingViewResolver的作用:组合所有的视图解析器的;详解见文末代码片段1:
    • 如何定制:我们可以自己给容器中添加一个视图解析器;自动的将其组合进来;详解见文末代码片段1:
  • Support for serving static resources, including support for WebJars (see below).支持静态资源文件夹路径,webjars ,即可以通过maven添加依赖的方式添加静态资源文件
  • Static index.html support.静态首页访问
  • Custom Favicon support (see below). 网页导航栏小图标
  • Automatic registration of(自动注册了)
    •  Converter:转换器,应用场景:Controller层public String Hello(User user)接受页面传来的值进行user对象的构建,这时属性存在各种类型转换
    • Formatter beans 格式化器,例如2018-10-1===Date;
@ConditionalOnProperty(prefix = "spring.mvc", name = "date‐format")//在文件中配置日期格
式化的规则
       
public Formatter<Date> dateFormatter() {        
return new DateFormatter(this.mvcProperties.getDateFormat());//日期格式化组件            
}

//自定义格式化器的加载方法
@Override
		public void addFormatters(FormatterRegistry registry) {
			for (Converter<?, ?> converter : getBeansOfType(Converter.class)) {
				registry.addConverter(converter);
			}
			for (GenericConverter converter : getBeansOfType(GenericConverter.class)) {
				registry.addConverter(converter);
			}
			for (Formatter<?> formatter : getBeansOfType(Formatter.class)) {
				registry.addFormatter(formatter);
			}
		}

		private <T> Collection<T> getBeansOfType(Class<T> type) {
			return this.beanFactory.getBeansOfType(type).values();
		}

自己添加的格式化器转换器,我们只需要放在容器中即可 

  • Support for HttpMessageConverters (see below).
    •  HttpMessageConverters:消息转换器,SpringMVC用来转换Http请求和响应的,例如:User对象返回到页面为Json数据
    • HttpMessageConverters 是从容器中确定;获取所有的HttpMessageConverter;
      自己给容器中添加HttpMessageConverter,只需要将自己的组件注册容器中
      @Bean,@Component)
  • Automatic registration of MessageCodesResolver (see below). 定义错误代码生成规则
  • Automatic use of a ConfigurableWebBindingInitializer bean (see below).我们可以配置一个ConfigurableWebBindingInitializer来替换默认的;(添加到容器)

org.springframework.boot.autoconfigure.web:web的所有自动场景;

5、如何修改SpringBoot的默认配置
模式:
1)、SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean、@Component)如
果有就用用户配置的,如果没有,才自动配置;如果有些组件可以有多个(ViewResolver)将用户配置的和自己默
认的组合起来;
2)、在SpringBoot中会有非常多的xxxConfigurer帮助我们进行扩展配置
3)、在SpringBoot中会有很多的xxxCustomizer帮助我们进行定制配置

If you want to keep Spring Boot MVC features, and you just want to add additional MVC configuration (interceptors, formatters, view controllers etc.) you can add your own @Configuration class of type WebMvcConfigurerAdapter, but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMappingRequestMappingHandlerAdapter or ExceptionHandlerExceptionResolver you can declare a WebMvcRegistrationsAdapter instance providing such components.

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.

 

代码片段1:

 /**
* WebMvcAutoConfiguration类
* 组合所有的视图解析器的,返回一个ContentNegotiatingViewResolver 
*/       
@Bean
@ConditionalOnBean(ViewResolver.class)
@ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
	ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
	resolver.setContentNegotiationManager(
			beanFactory.getBean(ContentNegotiationManager.class));
	// ContentNegotiatingViewResolver uses all the other view resolvers to locate
	// a view so it should have a high precedence
	resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return resolver;
}
//---------------------------查看ContentNegotiatingViewResolver能看到视图解析器方法 resolveViewName-----------

 public View resolveViewName(String viewName, Locale locale) throws Exception {
        RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
        Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
        List<MediaType> requestedMediaTypes = this.getMediaTypes(((ServletRequestAttributes)attrs).getRequest());
        if (requestedMediaTypes != null) {
            //方法的核心:获取候选的视图对象,然后选择一个最适合(匹配)的视图对象
            List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);
            View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);
            if (bestView != null) {
                return bestView;
            }
        }

        if (this.useNotAcceptableStatusCode) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("No acceptable view found; returning 406 (Not Acceptable) status code");
            }

            return NOT_ACCEPTABLE_VIEW;
        } else {
            this.logger.debug("No acceptable view found; returning null");
            return null;
        }
    }
//---------------------------------进一步查看 获取候选的视图对象的方法getCandidateViews------------------------
private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes)
			throws Exception {

		List<View> candidateViews = new ArrayList<>();
	//将对象的的所有视图解析器进行遍历从而获取所有视图	
   if (this.viewResolvers != null) {
			Assert.state(this.contentNegotiationManager != null, "No ContentNegotiationManager set");
			for (ViewResolver viewResolver : this.viewResolvers) {
				View view = viewResolver.resolveViewName(viewName, locale);
				if (view != null) {
					candidateViews.add(view);
				}
				for (MediaType requestedMediaType : requestedMediaTypes) {
					List<String> extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType);
					for (String extension : extensions) {
						String viewNameWithExtension = viewName + '.' + extension;
						view = viewResolver.resolveViewName(viewNameWithExtension, locale);
						if (view != null) {
							candidateViews.add(view);
						}
					}
				}
			}
		}
		if (!CollectionUtils.isEmpty(this.defaultViews)) {
			candidateViews.addAll(this.defaultViews);
		}
		return candidateViews;
	}
//-------------------------通过上面方法得出ContentNegotiatingViewResolver:组合所有的视图解析器的;-------------
//-------------------------但如何组合所有的试图解析器呢?见下面方法---------------------------------------------protected void initServletContext(ServletContext servletContext) {
		//通过BeanFactoryUtils类工具将所有视图解析器对象获取
       Collection<ViewResolver> matchingBeans =
				BeanFactoryUtils.beansOfTypeIncludingAncestors(obtainApplicationContext(), 
                ViewResolver.class).values();
		if (this.viewResolvers == null) {
			this.viewResolvers = new ArrayList<>(matchingBeans.size());
			for (ViewResolver viewResolver : matchingBeans) {
				if (this != viewResolver) {
					this.viewResolvers.add(viewResolver);
				}
			}
		}
		else {
			for (int i = 0; i < this.viewResolvers.size(); i++) {
				ViewResolver vr = this.viewResolvers.get(i);
				if (matchingBeans.contains(vr)) {
					continue;
				}
				String name = vr.getClass().getName() + i;
				obtainApplicationContext().getAutowireCapableBeanFactory().initializeBean(vr, name);
			}

		}
		if (this.viewResolvers.isEmpty()) {
			logger.warn("Did not find any ViewResolvers to delegate to; please configure them using the " +
					"'viewResolvers' property on the ContentNegotiatingViewResolver");
		}
		AnnotationAwareOrderComparator.sort(this.viewResolvers);
		this.cnmFactoryBean.setServletContext(servletContext);
	}

转载于:https://my.oschina.net/u/3864049/blog/2253114

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值