【源码】Spring —— PropertySource 解读

前言

property 键值对属性的抽象封装类

注意跟 @PropertySource 注解区分,@PropertySource@Configuration 搭配使用可以添加属性集到 Environment中

PropertySource

此处仅贴出部分 属性方法

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;
	}

	@SuppressWarnings("unchecked")
	public PropertySource(String name) {
		this(name, (T) new Object());
	}

	public String getName() {
		return this.name;
	}

	public T getSource() {
		return this.source;
	}

	public boolean containsProperty(String name) {
		return (getProperty(name) != null);
	}

	@Nullable
	public abstract Object getProperty(String name);

	// 内部类,可以理解为占位用的临时 PropertySource
	public static class StubPropertySource extends PropertySource<Object> {

		public StubPropertySource(String name) {
			super(name, new Object());
		}

		@Override
		@Nullable
		public String getProperty(String name) {
			return null;
		}
	}

	// 略

}

name 为维度,维护对应的 source,并提供对应的方法

EnumerablePropertySource

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

	public EnumerablePropertySource(String name, T source) {
		super(name, source);
	}

	protected EnumerablePropertySource(String name) {
		super(name);
	}

	@Override
	public boolean containsProperty(String name) {
		return ObjectUtils.containsElement(getPropertyNames(), name);
	}

	public abstract String[] getPropertyNames();

}

类如其名,拓展了 getPropertyNames 方法提供对 PropertyNames 的枚举功能,同时重写了 containsProperty 的实现,其下的子类主要以 source 的类型为维度展开拓展

ServletContextPropertySource

	public class ServletContextPropertySource extends EnumerablePropertySource<ServletContext> {

	public ServletContextPropertySource(String name, ServletContext servletContext) {
		super(name, servletContext);
	}

	@Override
	public String[] getPropertyNames() {
		return StringUtils.toStringArray(this.source.getInitParameterNames());
	}

	@Override
	@Nullable
	public String getProperty(String name) {
		return this.source.getInitParameter(name);
	}
}

sourceServletContextPropertySourcegetProperty 方法委托给了 ServletContextgetInitParameter 方法,实现了 getPropertyNames 方法

ServletConfigPropertySource

public class ServletConfigPropertySource extends EnumerablePropertySource<ServletConfig> {

	public ServletConfigPropertySource(String name, ServletConfig servletConfig) {
		super(name, servletConfig);
	}

	@Override
	public String[] getPropertyNames() {
		return StringUtils.toStringArray(this.source.getInitParameterNames());
	}

	@Override
	@Nullable
	public String getProperty(String name) {
		return this.source.getInitParameter(name);
	}
}

ServletContextPropertySource 类似,sourceServletConfig

MapPropertySource

public class MapPropertySource extends EnumerablePropertySource<Map<String, Object>> {

	public MapPropertySource(String name, Map<String, Object> source) {
		super(name, source);
	}

	@Override
	@Nullable
	public Object getProperty(String name) {
		return this.source.get(name);
	}

	@Override
	public boolean containsProperty(String name) {
		return this.source.containsKey(name);
	}

	@Override
	public String[] getPropertyNames() {
		return StringUtils.toStringArray(this.source.keySet());
	}

}

sourceMap<String, Object> 类型的 PropertySource ,最常用的 PropertySource ,注意 value 不能为 null,实现了 getPropertyNames 方法

SystemEnvironmentPropertySource
public class SystemEnvironmentPropertySource extends MapPropertySource {

	public SystemEnvironmentPropertySource(String name, Map<String, Object> source) {
		super(name, source);
	}
	
	@Override
	public boolean containsProperty(String name) {
		return (getProperty(name) != null);
	}

	@Override
	@Nullable
	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);
	}

	// ...

}

针对 SystemEnvironment 会进行特殊匹配处理,会在匹配失败后对 name 进行一系列转换后再尝试匹配

PropertiesPropertySource
public class PropertiesPropertySource extends MapPropertySource {

	@SuppressWarnings({"rawtypes", "unchecked"})
	public PropertiesPropertySource(String name, Properties source) {
		super(name, (Map) source);
	}

	protected PropertiesPropertySource(String name, Map<String, Object> source) {
		super(name, source);
	}

	@Override
	public String[] getPropertyNames() {
		synchronized (this.source) {
			return super.getPropertyNames();
		}
	}
}

sourcePropertiesPropertySourceProperties 本就是 Hashtable 的子类,相当于拓展了一种 MapPropertySource 的构造方法

ResourcePropertySource
public class ResourcePropertySource extends PropertiesPropertySource {

	@Nullable
	private final String resourceName;

	public ResourcePropertySource(String name, EncodedResource resource) throws IOException {
		super(name, PropertiesLoaderUtils.loadProperties(resource));
		this.resourceName = getNameForResource(resource.getResource());
	}

	public ResourcePropertySource(EncodedResource resource) throws IOException {
		super(getNameForResource(resource.getResource()), PropertiesLoaderUtils.loadProperties(resource));
		this.resourceName = null;
	}

	// 略
}

PropertiesPropertySource 的基础上拓展了对 EncodedResource 的解析,相当于对 PropertiesPropertySource 构造的拓展

类图

propertySource

总结

本文主要解读了 PropertySource 及其部分子类,可以看到它是对整个 属性键值对 的一种抽象,抽象出 getProperty 方法,让子类根据对不同类型 source 的实现提供对应的方法, 模板方法设计模式 的经典运用

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值