diff --git a/docs/Spring/clazz/Spring-PropertySources.md b/docs/Spring/clazz/Spring-PropertySources.md new file mode 100644 index 0000000..76223ae --- /dev/null +++ b/docs/Spring/clazz/Spring-PropertySources.md @@ -0,0 +1,509 @@ +# 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>`对象,主要是针对`List>` 进行的操作.换句话说就是对 list 操作的实现 + +- 类注解如下 + + + +```java +public class MutablePropertySources implements PropertySources { + + private final List> 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> iterator() { + return this.propertySourceList.iterator(); + } + + /** + * 获取 Spliterator 对象 + */ + @Override + public Spliterator> spliterator() { + return Spliterators.spliterator(this.propertySourceList, 0); + } + + /** + * 获取流 + */ + @Override + public Stream> 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> { + + /** + * Return a sequential {@link Stream} containing the property sources. + * 获取流 + * @since 5.1 + */ + default Stream> 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 { + + 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. + *

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. + *

Primarily for internal use, but given a collection of {@code PropertySource} objects, may be + * used as follows: + *

+	 * {@code List> sources = new ArrayList>();
+	 * 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"));
+	 * }
+ * 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. + *

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: + *

    + *
  • they are the same instance + *
  • the {@code name} properties for both objects are equal + *
+ *

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. + *

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 { + + 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) \ No newline at end of file diff --git a/images/spring/PropertySource.png b/images/spring/PropertySource.png new file mode 100644 index 0000000..b0a271a Binary files /dev/null and b/images/spring/PropertySource.png differ