You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
488 lines
15 KiB
488 lines
15 KiB
# Spring PropertySources
|
|
|
|
- Author: [HuiFer](https://github.com/huifer)
|
|
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
|
|
|
## MutablePropertySources
|
|
|
|
- 全路径: `org.springframework.core.env.MutablePropertySources`
|
|
|
|
- `MutablePropertySources`类内部存储了`List<PropertySource<?>>`对象,主要是针对`List<PropertySource<?>>` 进行的操作.换句话说就是对 list 操作的实现
|
|
|
|
- 类注解如下
|
|
|
|
```java
|
|
public class MutablePropertySources implements PropertySources {
|
|
|
|
private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<>();
|
|
|
|
|
|
/**
|
|
* Create a new {@link MutablePropertySources} object.
|
|
*
|
|
* 构造方法
|
|
*/
|
|
public MutablePropertySources() {
|
|
}
|
|
|
|
/**
|
|
* Create a new {@code MutablePropertySources} from the given propertySources
|
|
* object, preserving the original order of contained {@code PropertySource} objects.
|
|
* 构造方法, 传递一个集合, 将集合中的数据放入 {@code propertySourceList}.
|
|
*/
|
|
public MutablePropertySources(PropertySources propertySources) {
|
|
this();
|
|
// PropertySources 是一个迭代器接口的实现,通过循环取出信息放入到 propertySourceList 中
|
|
for (PropertySource<?> propertySource : propertySources) {
|
|
// 放入方法
|
|
addLast(propertySource);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* 获取迭代器对象
|
|
*/
|
|
@Override
|
|
public Iterator<PropertySource<?>> iterator() {
|
|
return this.propertySourceList.iterator();
|
|
}
|
|
|
|
/**
|
|
* 获取 Spliterator 对象
|
|
*/
|
|
@Override
|
|
public Spliterator<PropertySource<?>> spliterator() {
|
|
return Spliterators.spliterator(this.propertySourceList, 0);
|
|
}
|
|
|
|
/**
|
|
* 获取流
|
|
*/
|
|
@Override
|
|
public Stream<PropertySource<?>> stream() {
|
|
return this.propertySourceList.stream();
|
|
}
|
|
|
|
/**
|
|
* 判断是否存在 name
|
|
* @param name the {@linkplain PropertySource#getName() name of the property source} to find
|
|
*/
|
|
@Override
|
|
public boolean contains(String name) {
|
|
return this.propertySourceList.contains(PropertySource.named(name));
|
|
}
|
|
|
|
/**
|
|
* 获取 PropertySource 信息
|
|
* @param name the {@linkplain PropertySource#getName() name of the property source} to find
|
|
* @return
|
|
*/
|
|
@Override
|
|
@Nullable
|
|
public PropertySource<?> get(String name) {
|
|
// 获取 name 所在的索引位置
|
|
int index = this.propertySourceList.indexOf(PropertySource.named(name));
|
|
// get方法获取结果
|
|
return (index != -1 ? this.propertySourceList.get(index) : null);
|
|
}
|
|
|
|
|
|
/**
|
|
* Add the given property source object with highest precedence.
|
|
*
|
|
* 头插数据
|
|
*/
|
|
public void addFirst(PropertySource<?> propertySource) {
|
|
removeIfPresent(propertySource);
|
|
this.propertySourceList.add(0, propertySource);
|
|
}
|
|
|
|
/**
|
|
* Add the given property source object with lowest precedence.
|
|
*
|
|
* 尾插数据
|
|
*/
|
|
public void addLast(PropertySource<?> propertySource) {
|
|
removeIfPresent(propertySource);
|
|
this.propertySourceList.add(propertySource);
|
|
}
|
|
|
|
/**
|
|
* Add the given property source object with precedence immediately higher
|
|
* than the named relative property source.
|
|
*
|
|
* 在relativePropertySourceName的索引位置前添加数据
|
|
*/
|
|
public void addBefore(String relativePropertySourceName, PropertySource<?> propertySource) {
|
|
assertLegalRelativeAddition(relativePropertySourceName, propertySource);
|
|
removeIfPresent(propertySource);
|
|
int index = assertPresentAndGetIndex(relativePropertySourceName);
|
|
addAtIndex(index, propertySource);
|
|
}
|
|
|
|
/**
|
|
* Add the given property source object with precedence immediately lower
|
|
* than the named relative property source.
|
|
* 在relativePropertySourceName的索引位置后添加数据
|
|
*/
|
|
public void addAfter(String relativePropertySourceName, PropertySource<?> propertySource) {
|
|
assertLegalRelativeAddition(relativePropertySourceName, propertySource);
|
|
// 删除存在的数据
|
|
removeIfPresent(propertySource);
|
|
// 获取所有
|
|
int index = assertPresentAndGetIndex(relativePropertySourceName);
|
|
// 在索引+1出添加数据
|
|
addAtIndex(index + 1, propertySource);
|
|
}
|
|
|
|
/**
|
|
* Return the precedence of the given property source, {@code -1} if not found.
|
|
* 获取索引位置
|
|
*/
|
|
public int precedenceOf(PropertySource<?> propertySource) {
|
|
return this.propertySourceList.indexOf(propertySource);
|
|
}
|
|
|
|
/**
|
|
* Remove and return the property source with the given name, {@code null} if not found.
|
|
* 删除索引位置
|
|
* @param name the name of the property source to find and remove
|
|
*/
|
|
@Nullable
|
|
public PropertySource<?> remove(String name) {
|
|
// 获取索引
|
|
int index = this.propertySourceList.indexOf(PropertySource.named(name));
|
|
// 删除索引上的数据
|
|
return (index != -1 ? this.propertySourceList.remove(index) : null);
|
|
}
|
|
|
|
/**
|
|
* Replace the property source with the given name with the given property source object.
|
|
* 替换 name 的信息
|
|
* @param name the name of the property source to find and replace
|
|
* @param propertySource the replacement property source
|
|
* @throws IllegalArgumentException if no property source with the given name is present
|
|
* @see #contains
|
|
*/
|
|
public void replace(String name, PropertySource<?> propertySource) {
|
|
// 获取索引位置
|
|
int index = assertPresentAndGetIndex(name);
|
|
// 设置具体所应位置的值
|
|
this.propertySourceList.set(index, propertySource);
|
|
}
|
|
|
|
/**
|
|
* Return the number of {@link PropertySource} objects contained.
|
|
* 数量
|
|
*/
|
|
public int size() {
|
|
return this.propertySourceList.size();
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return this.propertySourceList.toString();
|
|
}
|
|
|
|
/**
|
|
* Ensure that the given property source is not being added relative to itself.
|
|
* 确保两个 PropertySource 的 name不相同
|
|
*/
|
|
protected void assertLegalRelativeAddition(String relativePropertySourceName, PropertySource<?> propertySource) {
|
|
// 获取 PropertySource 的名字
|
|
String newPropertySourceName = propertySource.getName();
|
|
// 历史名字和新的名字是否相同
|
|
if (relativePropertySourceName.equals(newPropertySourceName)) {
|
|
throw new IllegalArgumentException(
|
|
"PropertySource named '" + newPropertySourceName + "' cannot be added relative to itself");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove the given property source if it is present.
|
|
* 删除已存在的数据
|
|
*/
|
|
protected void removeIfPresent(PropertySource<?> propertySource) {
|
|
this.propertySourceList.remove(propertySource);
|
|
}
|
|
|
|
/**
|
|
* Add the given property source at a particular index in the list.
|
|
* 指定索引位置插入数据
|
|
*/
|
|
private void addAtIndex(int index, PropertySource<?> propertySource) {
|
|
removeIfPresent(propertySource);
|
|
this.propertySourceList.add(index, propertySource);
|
|
}
|
|
|
|
/**
|
|
* Assert that the named property source is present and return its index.
|
|
* 获取 name 所在的索引位置
|
|
* @param name {@linkplain PropertySource#getName() name of the property source} to find
|
|
* @throws IllegalArgumentException if the named property source is not present
|
|
*/
|
|
private int assertPresentAndGetIndex(String name) {
|
|
int index = this.propertySourceList.indexOf(PropertySource.named(name));
|
|
if (index == -1) {
|
|
throw new IllegalArgumentException("PropertySource named '" + name + "' does not exist");
|
|
}
|
|
return index;
|
|
}
|
|
|
|
}
|
|
```
|
|
|
|
## PropertySources
|
|
|
|
- 类路径: `org.springframework.core.env.PropertySources`
|
|
|
|
- 详细说明如下
|
|
|
|
```java
|
|
public interface PropertySources extends Iterable<PropertySource<?>> {
|
|
|
|
/**
|
|
* Return a sequential {@link Stream} containing the property sources.
|
|
* 获取流
|
|
* @since 5.1
|
|
*/
|
|
default Stream<PropertySource<?>> stream() {
|
|
return StreamSupport.stream(spliterator(), false);
|
|
}
|
|
|
|
/**
|
|
* Return whether a property source with the given name is contained.
|
|
* 判断是否存在 name
|
|
* @param name the {@linkplain PropertySource#getName() name of the property source} to find
|
|
*/
|
|
boolean contains(String name);
|
|
|
|
/**
|
|
* Return the property source with the given name, {@code null} if not found.
|
|
* 获取 PropertySource
|
|
* @param name the {@linkplain PropertySource#getName() name of the property source} to find
|
|
*/
|
|
@Nullable
|
|
PropertySource<?> get(String name);
|
|
|
|
}
|
|
```
|
|
|
|
## PropertySource
|
|
|
|
- 类路径: `org.springframework.core.env.PropertySource`
|
|
|
|
- 存有两个子类
|
|
1. StubPropertySource
|
|
2. ComparisonPropertySource 3. 调用`getSource`、`containsProperty`、`getProperty` 都会直接异常
|
|
|
|
```java
|
|
public abstract class PropertySource<T> {
|
|
|
|
protected final Log logger = LogFactory.getLog(getClass());
|
|
|
|
/**
|
|
* 属性名称
|
|
*/
|
|
protected final String name;
|
|
|
|
/**
|
|
* 值
|
|
*/
|
|
protected final T source;
|
|
|
|
|
|
/**
|
|
* Create a new {@code PropertySource} with the given name and source object.
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* Create a new {@code PropertySource} with the given name and with a new
|
|
* {@code Object} instance as the underlying source.
|
|
* <p>Often useful in testing scenarios when creating anonymous implementations
|
|
* that never query an actual source but rather return hard-coded values.
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
public PropertySource(String name) {
|
|
this(name, (T) new Object());
|
|
}
|
|
|
|
/**
|
|
* Return a {@code PropertySource} implementation intended for collection comparison purposes only.
|
|
* <p>Primarily for internal use, but given a collection of {@code PropertySource} objects, may be
|
|
* used as follows:
|
|
* <pre class="code">
|
|
* {@code List<PropertySource<?>> sources = new ArrayList<PropertySource<?>>();
|
|
* sources.add(new MapPropertySource("sourceA", mapA));
|
|
* sources.add(new MapPropertySource("sourceB", mapB));
|
|
* assert sources.contains(PropertySource.named("sourceA"));
|
|
* assert sources.contains(PropertySource.named("sourceB"));
|
|
* assert !sources.contains(PropertySource.named("sourceC"));
|
|
* }</pre>
|
|
* The returned {@code PropertySource} will throw {@code UnsupportedOperationException}
|
|
* if any methods other than {@code equals(Object)}, {@code hashCode()}, and {@code toString()}
|
|
* are called.
|
|
* @param name the name of the comparison {@code PropertySource} to be created and returned.
|
|
*/
|
|
public static PropertySource<?> named(String name) {
|
|
return new ComparisonPropertySource(name);
|
|
}
|
|
|
|
/**
|
|
* Return the name of this {@code PropertySource}.
|
|
*/
|
|
public String getName() {
|
|
return this.name;
|
|
}
|
|
|
|
/**
|
|
* Return the underlying source object for this {@code PropertySource}.
|
|
*/
|
|
public T getSource() {
|
|
return this.source;
|
|
}
|
|
|
|
/**
|
|
* Return whether this {@code PropertySource} contains the given name.
|
|
* <p>This implementation simply checks for a {@code null} return value
|
|
* from {@link #getProperty(String)}. Subclasses may wish to implement
|
|
* a more efficient algorithm if possible.
|
|
* @param name the property name to find
|
|
*/
|
|
public boolean containsProperty(String name) {
|
|
// getProperty 抽象方法子类实现
|
|
return (getProperty(name) != null);
|
|
}
|
|
|
|
/**
|
|
* Return the value associated with the given name,
|
|
* or {@code null} if not found.
|
|
* // getProperty 抽象方法子类实现
|
|
* @param name the property to find
|
|
* @see PropertyResolver#getRequiredProperty(String)
|
|
*/
|
|
@Nullable
|
|
public abstract Object getProperty(String name);
|
|
|
|
/**
|
|
* This {@code PropertySource} object is equal to the given object if:
|
|
* <ul>
|
|
* <li>they are the same instance
|
|
* <li>the {@code name} properties for both objects are equal
|
|
* </ul>
|
|
* <p>No properties other than {@code name} are evaluated.
|
|
*/
|
|
@Override
|
|
public boolean equals(@Nullable Object other) {
|
|
return (this == other || (other instanceof PropertySource &&
|
|
ObjectUtils.nullSafeEquals(this.name, ((PropertySource<?>) other).name)));
|
|
}
|
|
|
|
/**
|
|
* Return a hash code derived from the {@code name} property
|
|
* of this {@code PropertySource} object.
|
|
*/
|
|
@Override
|
|
public int hashCode() {
|
|
return ObjectUtils.nullSafeHashCode(this.name);
|
|
}
|
|
|
|
/**
|
|
* Produce concise output (type and name) if the current log level does not include
|
|
* debug. If debug is enabled, produce verbose output including the hash code of the
|
|
* PropertySource instance and every name/value property pair.
|
|
* <p>This variable verbosity is useful as a property source such as system properties
|
|
* or environment variables may contain an arbitrary number of property pairs,
|
|
* potentially leading to difficult to read exception and log messages.
|
|
* @see Log#isDebugEnabled()
|
|
*/
|
|
@Override
|
|
public String toString() {
|
|
if (logger.isDebugEnabled()) {
|
|
return getClass().getSimpleName() + "@" + System.identityHashCode(this) +
|
|
" {name='" + this.name + "', properties=" + this.source + "}";
|
|
}
|
|
else {
|
|
return getClass().getSimpleName() + " {name='" + this.name + "'}";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@code PropertySource} to be used as a placeholder in cases where an actual
|
|
* property source cannot be eagerly initialized at application context
|
|
* creation time. For example, a {@code ServletContext}-based property source
|
|
* must wait until the {@code ServletContext} object is available to its enclosing
|
|
* {@code ApplicationContext}. In such cases, a stub should be used to hold the
|
|
* intended default position/order of the property source, then be replaced
|
|
* during context refresh.
|
|
* @see org.springframework.context.support.AbstractApplicationContext#initPropertySources()
|
|
* @see org.springframework.web.context.support.StandardServletEnvironment
|
|
* @see org.springframework.web.context.support.ServletContextPropertySource
|
|
*/
|
|
public static class StubPropertySource extends PropertySource<Object> {
|
|
|
|
public StubPropertySource(String name) {
|
|
super(name, new Object());
|
|
}
|
|
|
|
/**
|
|
* Always returns {@code null}.
|
|
*/
|
|
@Override
|
|
@Nullable
|
|
public String getProperty(String name) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* A {@code PropertySource} implementation intended for collection comparison
|
|
* purposes.
|
|
*
|
|
* @see PropertySource#named(String)
|
|
*/
|
|
static class ComparisonPropertySource extends StubPropertySource {
|
|
|
|
// 异常信息
|
|
private static final String USAGE_ERROR =
|
|
"ComparisonPropertySource instances are for use with collection comparison only";
|
|
|
|
public ComparisonPropertySource(String name) {
|
|
super(name);
|
|
}
|
|
|
|
@Override
|
|
public Object getSource() {
|
|
// 抛异常
|
|
throw new UnsupportedOperationException(USAGE_ERROR);
|
|
}
|
|
|
|
@Override
|
|
public boolean containsProperty(String name) {
|
|
// 抛异常
|
|
throw new UnsupportedOperationException(USAGE_ERROR);
|
|
}
|
|
|
|
@Override
|
|
@Nullable
|
|
public String getProperty(String name) {
|
|
// 抛异常
|
|
throw new UnsupportedOperationException(USAGE_ERROR);
|
|
}
|
|
}
|
|
|
|
}
|
|
```
|
|
|
|
类图
|
|
|
|
![PropertySource.png](/images/spring/PropertySource.png)
|