博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring-core组件详解——PropertySource属性源
阅读量:6876 次
发布时间:2019-06-26

本文共 4466 字,大约阅读时间需要 14 分钟。

hot3.png

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

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

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

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

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

属性源体系图如下:

111021_nRNH_2624635.png

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

  1. StubPropertySource:占位属性源。

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

  2. 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);}

体系详解:

  1. PropertySource<T>:

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

  2. EnumerablePropertySource<T>:继承自PropertySource<T>。

    可枚举属性的属性源,额外定义了获取所有属性名称的方法

    public abstract String[] getPropertyNames();
  3. MapPropertySource:继承自EnumerablePropertySource<T>。

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

  4. PropertiesPropertySource:继承自MapPropertySource。

    以Properties(extends Hashtable<Object,Object>)对象作为源对象封装属性。

  5. 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);	}
  6. 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属性源本身只负责属性的存取,是不负责对命令行参数的解析的。

  7. SimpleCommandLinePropertySource:继承自CommandLinePropertySource<CommandLineArgs>。

    简单命令行属性源,使用SimpleCommandLineArgsParser解析器对象解析输入的String数组,把返回的CommandLineArgs对象作为属性的来源。

  8. JOptCommandLinePropertySource:

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

    net.sf.jopt-simple
    jopt-simple
    5.0.1

  9. CompositePropertySource:继承自EnumerablePropertySource<T>。

    合成属性源,内部持有一个Set<PropertySource<?>>属性源集合。因为每个属性源对象都有一个名称标识,那么当多个属性源对象共享同一个名称时,就需要CompositePropertySource对象把相同名称的所有属性源对象聚合到一起。

转载于:https://my.oschina.net/lixin91/blog/672315

你可能感兴趣的文章
Android源代码下载编译
查看>>
jsp---语句对象Statement
查看>>
RESTful API
查看>>
前端UI框架总结
查看>>
Atom 初识
查看>>
通向架构师的道路(第一天)之Apache整合Tomcat - lifetragedy的专栏 - 博客频道 - CSDN.NET...
查看>>
Javascript创建对象的7种模式
查看>>
Shell工作笔记01
查看>>
项目、软件开发过程中版本术语
查看>>
CSS实现背景透明,文字不透明(各浏览器兼容)
查看>>
【转】[大学引导]超级链接、字体颜色、音乐播放公式
查看>>
T-SQL中INSERT、UPDATE
查看>>
Linux下Nginx服务器配置Modsecurity实现Web应用防护系统
查看>>
用 zabbix 监测 snmptrap 的主动告警功能
查看>>
HDU1717 小数化分数2
查看>>
delphi 导入excel
查看>>
Linux下 FTP 常见错误 500 530等错误解决方法
查看>>
oracle asm
查看>>
VC基于单文档opengl框架
查看>>
openSUSE13.2安装ruby和rails
查看>>