在parse方法中
RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, parserContext);
//获取设置的ContentNegotiationManager对象
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
handlerMappingDef.setSource(source);
handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
handlerMappingDef.getPropertyValues().add("order", 0);
//为HandlerMapping设置ContentNegotiationManager属性
handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
其实在RequestMappingHandlerMapping中默认有一个ContentNegotiationManager对象
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
implements EmbeddedValueResolverAware {
private boolean useSuffixPatternMatch = true;
private boolean useRegisteredSuffixPatternMatch = false;
private boolean useTrailingSlashMatch = true;
private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();
我们去跟踪其getContentNegotiationManager方法
private RuntimeBeanReference getContentNegotiationManager(Element element, Object source, ParserContext parserContext) {
RuntimeBeanReference contentNegotiationManagerRef;
if (element.hasAttribute("content-negotiation-manager")) {//获取在指定属性上指定的ref对象
contentNegotiationManagerRef = new RuntimeBeanReference(element.getAttribute("content-negotiation-manager"));
}
else {//如果没有指定这个属性,则创建一个默认的
RootBeanDefinition factoryBeanDef = new RootBeanDefinition(ContentNegotiationManagerFactoryBean.class);
factoryBeanDef.setSource(source);
factoryBeanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
factoryBeanDef.getPropertyValues().add("mediaTypes", getDefaultMediaTypes());//指定MediaTypes
String beanName = "mvcContentNegotiationManager";
//将这个BeanDefinition注册到applicationContext的beanFactory上
parserContext.getReaderContext().getRegistry().registerBeanDefinition(beanName , factoryBeanDef);
//将bean实例化,并注册到spring 容器中(立个flag,以后再验证)
parserContext.registerComponent(new BeanComponentDefinition(factoryBeanDef, beanName));
contentNegotiationManagerRef = new RuntimeBeanReference(beanName);
}
return contentNegotiationManagerRef;
}
我们查看ContentNegotiationManagerFactoryBean的说明
根据文档可以看出,这个FactoryBean需要根据配置提供一个或者多个ContentNegotiationStrategy才能对ContentNegotiationiManager获取。默认注册的策略用来检查请求路径的后缀和请求头部的Accept参数
其实例化后执行的代码就在afterPorpertiesSet中
public void afterPropertiesSet() {
List<ContentNegotiationStrategy> strategies = new ArrayList<ContentNegotiationStrategy>();
if (this.favorPathExtension) {//true
PathExtensionContentNegotiationStrategy strategy;
if (this.servletContext != null) {//true 所以默认添加的策略就是这个Servlet...了
//而我们的mediaTypes已经在bean定义被指定了{json=application/json, xml=application/xml}
strategy = new ServletPathExtensionContentNegotiationStrategy(this.servletContext, this.mediaTypes);
} else {
strategy = new PathExtensionContentNegotiationStrategy(this.mediaTypes);
}
if (this.useJaf != null) {//null
strategy.setUseJaf(this.useJaf);
}
strategies.add(strategy);
}
//下面的判定全为false...
//这个FactoryBean.getObject方法返回的就是这个contentNegotiationManager了。。
this.contentNegotiationManager = new ContentNegotiationManager(strategies);
}
我们看一下我们的主角ContentNegotiationManager
这个类实现了两个不同的接口:ContentNegotiationStrategy以及MediaTypeFileExtensionResolver 它作为这两个接口的代理类,用于代理这两个接口的功能,里面存放着两个接口的集合
因为有一些类同时实现了这两种接口,所以在其构造方法中提供了相关处理,上面的ServletPathExtensionContentNegotiationStrategy就是这样的一个类。
public ContentNegotiationManager(ContentNegotiationStrategy... strategies) {
Assert.notEmpty(strategies, "At least one ContentNegotiationStrategy is expected");
this.contentNegotiationStrategies.addAll(Arrays.asList(strategies));
for (ContentNegotiationStrategy strategy : this.contentNegotiationStrategies) {
if (strategy instanceof MediaTypeFileExtensionResolver) {//判定为真则存入fileExtensionResolvers集合中
this.fileExtensionResolvers.add((MediaTypeFileExtensionResolver) strategy);
}
}
}
所以其解析MediaType的真正实现在ContentNegotiationStrategy中,这个Manager只是他们的委托