您的位置:首页 > 编程语言 > Java开发

spring-core组件详解——PropertySource属性源

2016-05-09 00:00 831 查看
所谓属性源,其实就是一个属性集合,它内部封装了多个name/value键值对,通过name可以获取与之对应的value值。

PropertySource属性源对象通常不单独使用,而是通过一个PropertySources(注意s)对象,我称它为属性源集合对象,由这个对象来统一管理。PropertySources其实就相当于一个Collection容器,其内部聚集了多个PropertySource属性源对象,且有序。它可以按序遍历内部持有的每个属性源,搜索name对应的value,找到即返回。

PropertySources属性源集合又跟PropertyResolver属性解决器协作,共同解决${}格式的属性占位符。

最后,总结一下PropertySource、PropertySources和PropertyResolver三者之间的关系:

属性解决器可以处理嵌套结构的占位符,而占位符对应的的值来自于PropertySources属性源集合,PropertySources负责搜索内部的每个PropertySource(它才是属性值的真正保存者)。

属性源体系图如下:



除以上体系之外,PropertySource还有2个内部类实现:

StubPropertySource:占位属性源。
这是一个只有名称标识,没有任何值的属性源,只用作占位符,当实际的属性源对象不能在ApplicationContext应用上下文创建的时候被立即初始化,则会使用它来占位,以保证属性源集合的搜索顺序。举个例子:在Web环境中,创建StandardServletEnvironment对象时,会先调用customPropertySources追加ServletConfig和ServletContext两个属性源对象,但是此时并没有这两个对象的引用(两个对象的引用通过initPropertySources初始化时传入),因此会创建StubPropertySource对象占位,当初始化时再用实际属性源替换掉(根据name匹配)占位对象。

ComparisonPropertySource:比较属性源,继承自StubPropertySource。
它只用作根据name获取属性源对象时比较。MutablePropertySources.get(String name)提供了根据名称获取属性源的接口,但是List接口只有通过索引获取元素(get),或者通过元素获取索引(indexOf)的接口。因此会先创建ComparisonPropertySource对象,indexOf通过equals比较获取属性源索引,再get获取真实的属性源。

public PropertySource<?> get(String name) {
int index = this.propertySourceList.indexOf(PropertySource.named(name));
return (index != -1 ? this.propertySourceList.get(index) : null);
}


体系详解:

PropertySource<T
7fe1
>:
所有属性源的抽象基类,内部包含2个属性:name名称为属性源对象的唯一标识;source源对象封装着name/value属性对。具体封装方式由子类实现决定,泛型T指定了源对象的具体类型。该类定义了组件的核心功能:判断name属性是否存在;根据name获取对应的value。另外,上文提到的两个内部类也在当前基类中定义。通过一个静态的named(name)方法,可以创建一个用于比较的ComparisonPropertySource对象。



EnumerablePropertySource<T>:继承自PropertySource<T>。
可枚举属性的属性源,额外定义了获取所有属性名称的方法

public abstract String[] getPropertyNames();


MapPropertySource:继承自EnumerablePropertySource<T>。
以Map<String, Object>对象作为源对象封装属性。这是一个直接可用的完整实现类。

PropertiesPropertySource:继承自MapPropertySource。
以Properties(extends Hashtable<Object,Object>)对象作为源对象封装属性。

SystemEnvironmentPropertySource:继承自MapPropertySource。
系统环境属性源,此属性源在根据name获取对应的value时,与父类实现不太一样。它认为name不区分大小写,且name中包含的'.'点与'_'下划线是等效的,因此在获取value之前,都会对name进行一次处理。
@Override
public Object getProperty(String name) {
// 解决属性名
String actualName = resolvePropertyName(name);
if (logger.isDebugEnabled() && !name.equals(actualName)) {
logger.debug(String.format("PropertySource [%s] does not contain '%s', but found equivalent '%s'",
getName(), name, actualName));
}
return super.getProperty(actualName);
}

private String resolvePropertyName(String name) {
Assert.notNull(name, "Property name must not be null");
// 如果source对象中存在此name,则直接返回
if (containsKey(name)) {
return name;
}
// source对象中不存在此name,则把name中的'.'替换成'_',再次尝试
String usName = name.replace('.', '_');
// 如果source对象中存在替换后的name,则返回替换后的name
if (!name.equals(usName) && containsKey(usName)) {
return usName;
}

// 还是没有则再次尝试原始name转大写
String ucName = name.toUpperCase();
if (!name.equals(ucName)) {
if (containsKey(ucName)) {
return ucName;
}
// 还是不存在,则转大写后,再'.'替换成'_'尝试
else {
String usUcName = ucName.replace('.', '_');
if (!ucName.equals(usUcName) && containsKey(usUcName)) {
return usUcName;
}
}
}
// 都不存在,则返回原始name
return name;
}

private boolean containsKey(String name) {
return (isSecurityManagerPresent() ? this.source.keySet().contains(name) : this.source.containsKey(name));
}

protected boolean isSecurityManagerPresent() {
return (System.getSecurityManager() != null);
}


CommandLinePropertySource:继承自EnumerablePropertySource<T>。
以输入命令行参数作为属性源的对象。命令行参数就是main方法传入的String[]数组值,在命令行中输入的字符串默认会以空格为分隔符被拆分成String数组。如:
java -dkey=value Test.class --name1=value1 --name2=value2 abc
"-dkey=value Test.class"代表虚拟机参数,而"--name1=value1 --name2=value2 abc"会以空格拆分传入main方法。
CommandLinePropertySource属性源内部分为选项参数和非选项参数,选项参数带有特定的前缀(一般为"--"),非选项参数则相反。命令行参数语法一般由解析器定义,如:
SimpleCommandLineArgsParser定义:选项参数的前缀为"--"。当然,我们也可以自定义解析器。
注意:CommandLinePropertySource属性源本身只负责属性的存取,是不负责对命令行参数的解析的。

SimpleCommandLinePropertySource:继承自CommandLinePropertySource<CommandLineArgs>。
简单命令行属性源,使用SimpleCommandLineArgsParser解析器对象解析输入的String数组,把返回的CommandLineArgs对象作为属性的来源。

JOptCommandLinePropertySource:
基于JOpt Simple的属性源实现,JOpt Simple是一个解析命令行选项参数的第三方库。坐标如下:

<dependency>
<groupId>net.sf.jopt-simple</groupId>
<artifactId>jopt-simple</artifactId>
<version>5.0.1</version>
</dependency>


CompositePropertySource:继承自EnumerablePropertySource<T>。
合成属性源,内部持有一个Set<PropertySource<?>>属性源集合。因为每个属性源对象都有一个名称标识,那么当多个属性源对象共享同一个名称时,就需要CompositePropertySource对象把相同名称的所有属性源对象聚合到一起。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring