SpringMvc的AnnotationDrivenBeanDefinitionParser的ContentNegotiationManager

在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只是他们的委托


阅读更多
个人分类: spring-实战
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭