spring之PropertySource

简介

PropertySource是一个抽象类,用于存放key-value键值对的抽象,value可以使任意类型,如:ServletContext、ServletConfig、Properties等。类结构简化如下:

public abstract class PropertySource<T> {
    //属性名称(不可更改)
	protected final String name;
    //属性值(不可更改)
	protected final T source;
    //构造函数
	public PropertySource(String name, T source) {
		Assert.hasText(name, "Property source name must contain at least one character");
		Assert.notNull(source, "Property source must not be null");
		this.name = name;
		this.source = source;
	}

重要的类继承关系如下:

在这里插入图片描述

EnumerablePropertySource

是PropertySource最重要的一个分支,大部分的实现类都继承于它, Enumerable表示可枚举的意思,新增抽象方法getPropertyNames()表示每个key都应该是可以枚举的,同时重写containsProperty()方法通过getPropertyNames()方法返回的key进行判断。

public abstract class EnumerablePropertySource<T> extends PropertySource<T> {

  /**
   * 重写通过调用getPropertyNames()方法返回的所有key中是否包含给定的name
   */
  @Override
  public boolean containsProperty(String name) {
  	return ObjectUtils.containsElement(getPropertyNames(), name);
  }

  /**
   * 返回所有的key,如MapPropertySource实现类返回source类型为Map所有key
   */
  public abstract String[] getPropertyNames();

MapPropertySource

这也是一个相对重要的实现类,其source类型为Map,实现了getProperty()方法,重写了containsProperty()、getPropertyNames()方法

public class MapPropertySource extends EnumerablePropertySource<Map<String, Object>> {
  /*
  * 从类型为Map<String, Object>的source获取值
  */
  @Override
  @Nullable
  public Object getProperty(String name) {
  	return this.source.get(name);
  }
 /**
 *  判断类型为Map的source是否包含某个key
 */
  @Override
  public boolean containsProperty(String name) {
  	return this.source.containsKey(name);
  }
 /**
 *  从类型为Map的source取出所有key
 */
  @Override
  public String[] getPropertyNames() {
  	return StringUtils.toStringArray(this.source.keySet());
  }
}

SystemEnvironmentPropertySource

继承自MapPropertySource,它的source也是一个map,但来源于系统环境。与MapPropertySource不同的是,取值时它将会忽略大小写,”.”和”_”将会转化,因此在获取value之前,都会对name进行一次处理。

public class SystemEnvironmentPropertySource extends MapPropertySource {

   /**
   * 根据属性名获取属性值
   */
   public Object getProperty(String name) {
       /**
       * 在获取属性值之前先对属性名解析
       */
   	String actualName = resolvePropertyName(name);
   	if (logger.isDebugEnabled() && !name.equals(actualName)) {
   		logger.debug("PropertySource '" + getName() + "' does not contain property '" + name +
   				"', but found equivalent '" + actualName + "'");
   	}
   	return super.getProperty(actualName);
   }

  /**
  * 解析属性名,
  */
   protected final String resolvePropertyName(String name) {
   	Assert.notNull(name, "Property name must not be null");
   	//转化属性名,如将"."转化为"-",将"-"转化为"_"等
   	String resolvedName = checkPropertyName(name);
   	if (resolvedName != null) {
   		return resolvedName;
   	}
   	//将属性名转换成大写再重新匹配转化
   	String uppercasedName = name.toUpperCase();
   	if (!name.equals(uppercasedName)) {
   		resolvedName = checkPropertyName(uppercasedName);
   		if (resolvedName != null) {
   			return resolvedName;
   		}
   	}
   	return name;
   }

   @Nullable
   private String checkPropertyName(String name) {
   	// 如果已经存在直接返回
   	if (containsKey(name)) {
   		return name;
   	}
   	// "."与"_"等价
   	String noDotName = name.replace('.', '_');
   	if (!name.equals(noDotName) && containsKey(noDotName)) {
   		return noDotName;
   	}
   	// / "-"与"_"等价
   	String noHyphenName = name.replace('-', '_');
   	if (!name.equals(noHyphenName) && containsKey(noHyphenName)) {
   		return noHyphenName;
   	}
   	// 继续寻找替换 "-"与"_"等价
   	String noDotNoHyphenName = noDotName.replace('-', '_');
   	if (!noDotName.equals(noDotNoHyphenName) && containsKey(noDotNoHyphenName)) {
   		return noDotNoHyphenName;
   	}
   	return null;
   }
}

PropertiesPropertySource

MapPropertySource没太大区别,唯一的操作就是对source进行了加锁,从而避免并发场景下的线程不安全因素。

public class PropertiesPropertySource extends MapPropertySource {
  /**
  * 加锁,并发控制
  */
   @Override
   public String[] getPropertyNames() {
   	synchronized (this.source) {
   		return super.getPropertyNames();
   	}
   }

}

ResourcePropertySource

继承至PropertiesPropertySource,source来自于一个Resource资源,构造函数比较丰富,便于开发者使用

public class ResourcePropertySource extends PropertiesPropertySource {
/**
* 构造函数入参resource为资源,通过PropertiesLoaderUtils加载资源成Properties(继承至Hashtable)
*/
public ResourcePropertySource(String name, Resource resource) throws IOException {
		super(name, PropertiesLoaderUtils.loadProperties(new EncodedResource(resource)));
		this.resourceName = getNameForResource(resource);
	}

}

ServletContextPropertySource

source 为 ServletContext,getProperty 方法委托给了ServletContext 的 getInitParameter方法用于访问Servlet上下文信息InitParameters

public class ServletContextPropertySource extends EnumerablePropertySource<ServletContext> {
     /**
     * ServletContext InitParameterName的key
     */
	@Override
	public String[] getPropertyNames() {
		return StringUtils.toStringArray(this.source.getInitParameterNames());
	}
    /**
    * ServletContext通过name获取属性值
    */  
	@Override
	@Nullable
	public String getProperty(String name) {
		return this.source.getInitParameter(name);
	}

}

MutablePropertySources

它是PropertySource的一个复数形式,它如同一个容器可以包含一个或者多个PropertySource。并且提供对他们操作的方法,它更像是一个管理器,管理着所有的PropertySource,如:提供增、删、改、查方法。

public class MutablePropertySources implements PropertySources {
/**
 * 新增PropertySource
*/
public void addFirst(PropertySource<?> propertySource) {
		synchronized (this.propertySourceList) {
			removeIfPresent(propertySource);
			this.propertySourceList.add(0, propertySource);
		}
	}

}

/**
* 删除
*/
public PropertySource<?> remove(String name) {
	synchronized (this.propertySourceList) {
		int index = this.propertySourceList.indexOf(PropertySource.named(name));
		return (index != -1 ? this.propertySourceList.remove(index) : null);
	}
}

/**
* 修改
*/
public void replace(String name, PropertySource<?> propertySource) {
	synchronized (this.propertySourceList) {
		int index = assertPresentAndGetIndex(name);
		this.propertySourceList.set(index, propertySource);
	}
}
/**
* 查找
*/	
public PropertySource<?> get(String name) {
	for (PropertySource<?> propertySource : this.propertySourceList) {
		if (propertySource.getName().equals(name)) {
			return propertySource;
		}
	}
	return null;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值