Spring源码情操陶冶-PropertyPlaceholderBeanDefinitionParser注解配置解析器

本文针对spring配置的context:property-placeholder作下简单的分析,承接前文Spring源码情操陶冶-自定义节点的解析

spring配置文件应用

<context:property-placeholder location="classpath:context.properties">

PropertyPlaceholderBeanDefinitionParser-继承关系

配置文件解析类的继承关系如下

* AbstractBeanDefinitionParser
	* AbstractSingleBeanDefinitionParser
		* AbstractPropertyLoadingBeanDefinitionParser
			* PropertyPlaceholderBeanDefinitionParser

所以我们将从父类开始慢慢剖析,方便理解的全面

AbstractBeanDefinitionParser-配置文件解析抽象类

直接查看主方法parse()

	public final BeanDefinition parse(Element element, ParserContext parserContext) {
		//模板方法,供子类调用,包装成AbstractBeanDefinition对象
		AbstractBeanDefinition definition = parseInternal(element, parserContext);
		if (definition != null && !parserContext.isNested()) {
			try {
				//生成唯一id
				String id = resolveId(element, definition, parserContext);
				if (!StringUtils.hasText(id)) {
					parserContext.getReaderContext().error(
							"Id is required for element '" + parserContext.getDelegate().getLocalName(element)
									+ "' when used as a top-level tag", element);
				}
				String[] aliases = new String[0];
				//解析context:property-holder的name属性,并支持,分隔
				String name = element.getAttribute(NAME_ATTRIBUTE);
				if (StringUtils.hasLength(name)) {
					aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
				}
				//包装为BeanDefinitionHolder对象
				BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
				//注册到bean工厂中
				registerBeanDefinition(holder, parserContext.getRegistry());
				//执行事件
				if (shouldFireEvents()) {
					BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
					//目前为空
					postProcessComponentDefinition(componentDefinition);

                                        //保存至containingComponents栈中								
                                        parserContext.registerComponent(componentDefinition);
				}
			}
			catch (BeanDefinitionStoreException ex) {
				parserContext.getReaderContext().error(ex.getMessage(), element);
				return null;
			}
		}
		return definition;
	}

主要的工作由子类AbstractSingleBeanDefinitionParser#parseInternal()方法来处理

AbstractSingleBeanDefinitionParser#parseInternal-初始解析操作

此方法主要是初始化一些准备工作,并仍采用模板方法doParse()方法供子类去实现解析操作

protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
		//类似于StringBuilder帮助创建beanDefinition
		BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
		//为null
		String parentName = getParentName(element);
		if (parentName != null) {
			builder.getRawBeanDefinition().setParentName(parentName);
		}
		//子类可复写此方法,譬如PropertyOverrideBeanDefinitionParser/PropertyPlaceholderBeanDefinitionParser
		Class<?> beanClass = getBeanClass(element);
		if (beanClass != null) {
			//设置beanClass
			builder.getRawBeanDefinition().setBeanClass(beanClass);
		}
		else {
			String beanClassName = getBeanClassName(element);
			if (beanClassName != null) {
				builder.getRawBeanDefinition().setBeanClassName(beanClassName);
			}
		}
		builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
		if (parserContext.isNested()) {
			// Inner bean definition must receive same scope as containing bean.
			builder.setScope(parserContext.getContainingBeanDefinition().getScope());
		}
		//是否需要随spring上下文设置lazy-init属性
		if (parserContext.isDefaultLazyInit()) {
			// Default-lazy-init applies to custom bean definitions as well.
			builder.setLazyInit(true);
		}
		//供子类调用实现解析,并传入BeanDefinitionBuilder对象
		doParse(element, parserContext, builder);
		return builder.getBeanDefinition();
	}

AbstractPropertyLoadingBeanDefinitionParser#doParse-基础解析

查看了下官方注释,对此类的解释是解析context:property-....节点的抽象类,此处可指PropertyOverrideBeanDefinitionParser/PropertyPlaceholderBeanDefinitionParser,可对此方法进行扩展,代码如下

	@Override
	protected void doParse(Element element, BeanDefinitionBuilder builder) {
		//获取location属性,支持,分隔,表明指定读取配置文件的路径
		String location = element.getAttribute("location");
		if (StringUtils.hasLength(location)) {
			String[] locations = StringUtils.commaDelimitedListToStringArray(location);
			builder.addPropertyValue("locations", locations);
		}
		//获取properties-ref属性,设置properties文件的引用名
		String propertiesRef = element.getAttribute("properties-ref");
		if (StringUtils.hasLength(propertiesRef)) {
			builder.addPropertyReference("properties", propertiesRef);
		}
		//获取file-encoding属性,文件解析字符编码集
		String fileEncoding = element.getAttribute("file-encoding");
		if (StringUtils.hasLength(fileEncoding)) {
			builder.addPropertyValue("fileEncoding", fileEncoding);
		}
		//获取order属性,用于排序
		String order = element.getAttribute("order");
		if (StringUtils.hasLength(order)) {
			builder.addPropertyValue("order", Integer.valueOf(order));
		}
		//获取ignore-resource-not-found属性,默认为false,表明找不到资源是否往外抛异常
		builder.addPropertyValue("ignoreResourceNotFound",
				Boolean.valueOf(element.getAttribute("ignore-resource-not-found")));
		//获取local-override属性,默认为false,true表明先使用文件中的属性,找不到再使用环境变量中的属性
		builder.addPropertyValue("localOverride",
				Boolean.valueOf(element.getAttribute("local-override")));

		builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
	}

PropertyPlaceholderBeanDefinitionParser-抽象方法的扩展

复写的抽象方法有两处,分别为getBeanClass()doParse()方法

  • getBeanClass(Element element)
    指定解析文件的beanClass,beanClass均是BeanFactoryPostProcessor接口的实现类,代码如下
protected Class<?> getBeanClass(Element element) {
		//获取system-properties-mode属性是否为ENVIRONMENT,是则采用PropertySourcesPlaceholderConfigurer.class
		if (element.getAttribute(SYSTEM_PROPERTIES_MODE_ATTRIB).equals(SYSTEM_PROPERTIES_MODE_DEFAULT)) {
			return PropertySourcesPlaceholderConfigurer.class;
		}

		//默认为PropertyPlaceholderConfigurer.class作为beanClass
		return PropertyPlaceholderConfigurer.class;
	}
  • doParse(Element element, BeanDefinitionBuilder builder)
    在父类的基础上再加几个属性判断
protected void doParse(Element element, BeanDefinitionBuilder builder) {
		super.doParse(element, builder);
		//获取ignore-unresolvable属性,默认为false,true代表解析不了属性不抛异常
		builder.addPropertyValue("ignoreUnresolvablePlaceholders",
				Boolean.valueOf(element.getAttribute("ignore-unresolvable")));
		//获取system-properties-mode属性
		String systemPropertiesModeName = element.getAttribute(SYSTEM_PROPERTIES_MODE_ATTRIB);
		if (StringUtils.hasLength(systemPropertiesModeName) &&
				!systemPropertiesModeName.equals(SYSTEM_PROPERTIES_MODE_DEFAULT)) {
			builder.addPropertyValue("systemPropertiesModeName", "SYSTEM_PROPERTIES_MODE_"+systemPropertiesModeName);
		}
	}

小结

  1. PropertyPlaceholderBeanDefinitionParser的作用是初始化配置文件的解析策略,方便spring在invokeBeanFactoryPostProcessors()中解析${}属性使用,具体可看>>>Spring源码情操陶冶-AbstractApplicationContext#invokeBeanFactoryPostProcessors

  2. 真正的解析${}这样格式的类是PropertyPlaceholderConfigurer.class或者是PropertySourcesPlaceholderConfigurer.class,前者适合spring 3.0之前,后者适合spring 3.1之后;
    前者是默认的实现,后者如果指定local-override为true,则优先找寻本地属性(文件属性),找不到的情况下再找寻环境属性(Environment)

  3. context:property-placeholder的属性

  • location-文件资源路径,支持classpath路径,且可指定多个,以,分隔
  • file-encoding-文件读取编码
  • properties-ref-属性配置文件应用名
  • order-排序属性
  • ignore-resource-not-found-默认为false,表明找不到资源是否往外抛异常
  • local-override-默认为false,表示优先查找文件(Properties)的属性,不存在则再找寻本地的属性(System),反之则是先本地后文件
  • ignore-unresolvable-默认为false,true代表解析不了属性不抛异常
posted @ 2017-06-12 17:23  南柯问天  阅读(609)  评论(0编辑  收藏  举报