parent
61ef217374
commit
bdfafcad7e
@ -0,0 +1,127 @@
|
||||
# Spring CommandLinePropertySource
|
||||
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- 类全路径: `org.springframework.core.env.CommandLinePropertySource`
|
||||
- 作用: 用来存储命令行参数
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```java
|
||||
public abstract class CommandLinePropertySource<T> extends EnumerablePropertySource<T> {
|
||||
|
||||
public static final String COMMAND_LINE_PROPERTY_SOURCE_NAME = "commandLineArgs";
|
||||
|
||||
public static final String DEFAULT_NON_OPTION_ARGS_PROPERTY_NAME = "nonOptionArgs";
|
||||
|
||||
|
||||
private String nonOptionArgsPropertyName = DEFAULT_NON_OPTION_ARGS_PROPERTY_NAME;
|
||||
|
||||
|
||||
|
||||
public CommandLinePropertySource(T source) {
|
||||
// 命令行参数, 属性值
|
||||
super(COMMAND_LINE_PROPERTY_SOURCE_NAME, source);
|
||||
}
|
||||
|
||||
public CommandLinePropertySource(String name, T source) {
|
||||
// 参数名称, 参数值
|
||||
super(name, source);
|
||||
}
|
||||
|
||||
|
||||
public void setNonOptionArgsPropertyName(String nonOptionArgsPropertyName) {
|
||||
this.nonOptionArgsPropertyName = nonOptionArgsPropertyName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean containsProperty(String name) {
|
||||
// 输入值是否等于nonOptionArgs
|
||||
if (this.nonOptionArgsPropertyName.equals(name)) {
|
||||
// 等于后判断参数列表是否为空
|
||||
return !this.getNonOptionArgs().isEmpty();
|
||||
}
|
||||
// 是否存在 name 属性
|
||||
return this.containsOption(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public final String getProperty(String name) {
|
||||
if (this.nonOptionArgsPropertyName.equals(name)) {
|
||||
// 获取 非可选项参数列表
|
||||
Collection<String> nonOptionArguments = this.getNonOptionArgs();
|
||||
if (nonOptionArguments.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
// 可选参数命令行参数
|
||||
return StringUtils.collectionToCommaDelimitedString(nonOptionArguments);
|
||||
}
|
||||
}
|
||||
Collection<String> optionValues = this.getOptionValues(name);
|
||||
if (optionValues == null) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
// 命令行参数
|
||||
return StringUtils.collectionToCommaDelimitedString(optionValues);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 是否存在 name 的命令行参数
|
||||
*/
|
||||
protected abstract boolean containsOption(String name);
|
||||
|
||||
/**
|
||||
* 获取参数列表集合
|
||||
*/
|
||||
@Nullable
|
||||
protected abstract List<String> getOptionValues(String name);
|
||||
|
||||
/**
|
||||
* 获取 non-option 参数列表
|
||||
*/
|
||||
protected abstract List<String> getNonOptionArgs();
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## getOptionValues
|
||||
|
||||
```java
|
||||
/**
|
||||
* Return the collection of values associated with the command line option having the
|
||||
* given name.
|
||||
* <ul>
|
||||
* <li>if the option is present and has no argument (e.g.: "--foo"), return an empty
|
||||
* collection ({@code []})</li>
|
||||
* <li>if the option is present and has a single value (e.g. "--foo=bar"), return a
|
||||
* collection having one element ({@code ["bar"]})</li>
|
||||
* <li>if the option is present and the underlying command line parsing library
|
||||
* supports multiple arguments (e.g. "--foo=bar --foo=baz"), return a collection
|
||||
* having elements for each value ({@code ["bar", "baz"]})</li>
|
||||
* <li>if the option is not present, return {@code null}</li>
|
||||
* </ul>
|
||||
*
|
||||
* 获取参数列表集合
|
||||
*/
|
||||
@Nullable
|
||||
protected abstract List<String> getOptionValues(String name);
|
||||
```
|
||||
|
||||
|
||||
|
||||
阅读注释可以知道该方法可以获取命令行参数的列表.
|
||||
|
||||
- 如 `--foo`作为开头当输入命令行为 `--foo=bar --foo=baz` 在输入参数名称 `foo` 会得到数据`bar,baz`
|
@ -0,0 +1,44 @@
|
||||
# Spring ComparisonPropertySource
|
||||
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- 整体代码如下.
|
||||
- 下面几个调用方法会直接抛出异常
|
||||
1. getSource
|
||||
1. containsProperty
|
||||
1. getProperty
|
||||
|
||||
```java
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
@ -0,0 +1,105 @@
|
||||
# Spring CompositePropertySource
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- 全路径: `org.springframework.core.env.CompositePropertySource`
|
||||
|
||||
- 整体代码如下
|
||||
```java
|
||||
public class CompositePropertySource extends EnumerablePropertySource<Object> {
|
||||
|
||||
/**
|
||||
* set 集合
|
||||
*/
|
||||
private final Set<PropertySource<?>> propertySources = new LinkedHashSet<>();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code CompositePropertySource}.
|
||||
* @param name the name of the property source
|
||||
*/
|
||||
public CompositePropertySource(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object getProperty(String name) {
|
||||
// 循环
|
||||
for (PropertySource<?> propertySource : this.propertySources) {
|
||||
// 获取存储内容
|
||||
Object candidate = propertySource.getProperty(name);
|
||||
if (candidate != null) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsProperty(String name) {
|
||||
for (PropertySource<?> propertySource : this.propertySources) {
|
||||
// 是否存在name
|
||||
if (propertySource.containsProperty(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getPropertyNames() {
|
||||
Set<String> names = new LinkedHashSet<>();
|
||||
for (PropertySource<?> propertySource : this.propertySources) {
|
||||
// 类型不同抛出异常
|
||||
if (!(propertySource instanceof EnumerablePropertySource)) {
|
||||
throw new IllegalStateException(
|
||||
"Failed to enumerate property names due to non-enumerable property source: " + propertySource);
|
||||
}
|
||||
// 批量添加
|
||||
names.addAll(Arrays.asList(((EnumerablePropertySource<?>) propertySource).getPropertyNames()));
|
||||
}
|
||||
// 转换成 array
|
||||
return StringUtils.toStringArray(names);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add the given {@link PropertySource} to the end of the chain.
|
||||
* @param propertySource the PropertySource to add
|
||||
*/
|
||||
public void addPropertySource(PropertySource<?> propertySource) {
|
||||
this.propertySources.add(propertySource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given {@link PropertySource} to the start of the chain.
|
||||
* @param propertySource the PropertySource to add
|
||||
* @since 4.1
|
||||
*/
|
||||
public void addFirstPropertySource(PropertySource<?> propertySource) {
|
||||
// 头插
|
||||
List<PropertySource<?>> existing = new ArrayList<>(this.propertySources);
|
||||
this.propertySources.clear();
|
||||
this.propertySources.add(propertySource);
|
||||
this.propertySources.addAll(existing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all property sources that this composite source holds.
|
||||
* @since 4.1.1
|
||||
*/
|
||||
public Collection<PropertySource<?>> getPropertySources() {
|
||||
return this.propertySources;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + " {name='" + this.name + "', propertySources=" + this.propertySources + "}";
|
||||
}
|
||||
|
||||
}
|
||||
```
|
@ -0,0 +1,46 @@
|
||||
# Spring EnumerablePropertySource
|
||||
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
- 全路径: `org.springframework.core.env.EnumerablePropertySource`
|
||||
- 在这个类中定义了一个抽象方法`getPropertyNames` 用来获取所有的 property 的名称
|
||||
|
||||
```java
|
||||
public abstract String[] getPropertyNames();
|
||||
```
|
||||
- 整体代码如下
|
||||
```java
|
||||
public abstract class EnumerablePropertySource<T> extends PropertySource<T> {
|
||||
|
||||
public EnumerablePropertySource(String name, T source) {
|
||||
super(name, source);
|
||||
}
|
||||
|
||||
protected EnumerablePropertySource(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return whether this {@code PropertySource} contains a property with the given name.
|
||||
* <p>This implementation checks for the presence of the given name within the
|
||||
* {@link #getPropertyNames()} array.
|
||||
*
|
||||
* 在属性列表中是否存在 properties
|
||||
* @param name the name of the property to find
|
||||
*/
|
||||
@Override
|
||||
public boolean containsProperty(String name) {
|
||||
return ObjectUtils.containsElement(getPropertyNames(), name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the names of all properties contained by the
|
||||
* 获取所有的 properties 名称
|
||||
* {@linkplain #getSource() source} object (never {@code null}).
|
||||
*/
|
||||
public abstract String[] getPropertyNames();
|
||||
|
||||
}
|
||||
```
|
@ -0,0 +1,43 @@
|
||||
# Spring MapPropertySource
|
||||
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- 类全路径: `org.springframework.core.env.MapPropertySource`
|
||||
- 内部数据结构是一个`Map<String,Object>`
|
||||
这是一个对map的操作.
|
||||
|
||||
- 整体代码如下.
|
||||
|
||||
```java
|
||||
|
||||
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) {
|
||||
// 从map中获取 name 对应的value
|
||||
return this.source.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsProperty(String name) {
|
||||
// 判断是否存在 name 属性
|
||||
return this.source.containsKey(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getPropertyNames() {
|
||||
// 互殴去 map 的所有key
|
||||
return StringUtils.toStringArray(this.source.keySet());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
@ -0,0 +1,112 @@
|
||||
# Spring MockPropertySource
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- 内部 source 是 Properties 类型
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## withProperty
|
||||
|
||||
- 设置属性名称和属性值
|
||||
|
||||
```java
|
||||
public MockPropertySource withProperty(String name, Object value) {
|
||||
this.setProperty(name, value);
|
||||
return this;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## setProperty
|
||||
|
||||
```java
|
||||
public void setProperty(String name, Object value) {
|
||||
this.source.put(name, value);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 完整代码
|
||||
|
||||
|
||||
|
||||
```java
|
||||
public class MockPropertySource extends PropertiesPropertySource {
|
||||
|
||||
/**
|
||||
* {@value} is the default name for {@link MockPropertySource} instances not
|
||||
* otherwise given an explicit name.
|
||||
* @see #MockPropertySource()
|
||||
* @see #MockPropertySource(String)
|
||||
*/
|
||||
public static final String MOCK_PROPERTIES_PROPERTY_SOURCE_NAME = "mockProperties";
|
||||
|
||||
/**
|
||||
* Create a new {@code MockPropertySource} named {@value #MOCK_PROPERTIES_PROPERTY_SOURCE_NAME}
|
||||
* that will maintain its own internal {@link Properties} instance.
|
||||
*/
|
||||
public MockPropertySource() {
|
||||
this(new Properties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code MockPropertySource} with the given name that will
|
||||
* maintain its own internal {@link Properties} instance.
|
||||
* @param name the {@linkplain #getName() name} of the property source
|
||||
*/
|
||||
public MockPropertySource(String name) {
|
||||
this(name, new Properties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code MockPropertySource} named {@value #MOCK_PROPERTIES_PROPERTY_SOURCE_NAME}
|
||||
* and backed by the given {@link Properties} object.
|
||||
* @param properties the properties to use
|
||||
*/
|
||||
public MockPropertySource(Properties properties) {
|
||||
this(MOCK_PROPERTIES_PROPERTY_SOURCE_NAME, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code MockPropertySource} with the given name and backed by the given
|
||||
* {@link Properties} object.
|
||||
* @param name the {@linkplain #getName() name} of the property source
|
||||
* @param properties the properties to use
|
||||
*/
|
||||
public MockPropertySource(String name, Properties properties) {
|
||||
super(name, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given property on the underlying {@link Properties} object.
|
||||
*/
|
||||
public void setProperty(String name, Object value) {
|
||||
// map 操作
|
||||
this.source.put(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient synonym for {@link #setProperty} that returns the current instance.
|
||||
* Useful for method chaining and fluent-style use.
|
||||
* 设置属性名称和属性值
|
||||
* @return this {@link MockPropertySource} instance
|
||||
*/
|
||||
public MockPropertySource withProperty(String name, Object value) {
|
||||
this.setProperty(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
```
|
@ -0,0 +1,35 @@
|
||||
# Spring PropertiesPropertySource
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- 全路径: `org.springframework.core.env.PropertiesPropertySource`
|
||||
|
||||
|
||||
|
||||
- Properties 是map结构。可以做类型转换.
|
||||
- getPropertyNames 就转换成了父类MapPropertySource的方法了
|
||||
- map.keySet()
|
||||
|
||||
```java
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
```
|
@ -0,0 +1,241 @@
|
||||
# Spring ResourcePropertySource
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- 全路径: `org.springframework.core.io.support.ResourcePropertySource`
|
||||
|
||||
- source 依然是map结构
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## getNameForResource
|
||||
|
||||
```java
|
||||
private static String getNameForResource(Resource resource) {
|
||||
// 获取 resource 的介绍
|
||||
String name = resource.getDescription();
|
||||
if (!StringUtils.hasText(name)) {
|
||||
// 短类名+@+hashcode
|
||||
name = resource.getClass().getSimpleName() + "@" + System.identityHashCode(resource);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## withName
|
||||
|
||||
- 创建 ResourcePropertySource 对象, 根据 name 属性
|
||||
|
||||
```java
|
||||
public ResourcePropertySource withName(String name) {
|
||||
if (this.name.equals(name)) {
|
||||
return this;
|
||||
}
|
||||
// Store the original resource name if necessary...
|
||||
if (this.resourceName != null) {
|
||||
if (this.resourceName.equals(name)) {
|
||||
return new ResourcePropertySource(this.resourceName, null, this.source);
|
||||
}
|
||||
else {
|
||||
return new ResourcePropertySource(name, this.resourceName, this.source);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Current name is resource name -> preserve it in the extra field...
|
||||
return new ResourcePropertySource(name, this.name, this.source);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 构造函数
|
||||
|
||||
- 通过 location 字符串读取 resource
|
||||
|
||||
```java
|
||||
public ResourcePropertySource(String name, String location, ClassLoader classLoader) throws IOException {
|
||||
// 默认资源读取器读取 location 转换成 resource
|
||||
this(name, new DefaultResourceLoader(classLoader).getResource(location));
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
- 读取 resource 信息进行存储
|
||||
|
||||
```java
|
||||
public ResourcePropertySource(String name, EncodedResource resource) throws IOException {
|
||||
// 设置 name + map 对象
|
||||
// map 对象是 资源信息
|
||||
super(name, PropertiesLoaderUtils.loadProperties(resource));
|
||||
// 获取 resource name
|
||||
this.resourceName = getNameForResource(resource.getResource());
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 完整代码
|
||||
|
||||
```java
|
||||
public class ResourcePropertySource extends PropertiesPropertySource {
|
||||
|
||||
/** The original resource name, if different from the given name. */
|
||||
@Nullable
|
||||
private final String resourceName;
|
||||
|
||||
|
||||
/**
|
||||
* Create a PropertySource having the given name based on Properties
|
||||
* loaded from the given encoded resource.
|
||||
*/
|
||||
public ResourcePropertySource(String name, EncodedResource resource) throws IOException {
|
||||
// 设置 name + map 对象
|
||||
// map 对象是 资源信息
|
||||
super(name, PropertiesLoaderUtils.loadProperties(resource));
|
||||
// 获取 resource name
|
||||
this.resourceName = getNameForResource(resource.getResource());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a PropertySource based on Properties loaded from the given resource.
|
||||
* The name of the PropertySource will be generated based on the
|
||||
* {@link Resource#getDescription() description} of the given resource.
|
||||
*/
|
||||
public ResourcePropertySource(EncodedResource resource) throws IOException {
|
||||
// 设置 key: name, resource 的 name
|
||||
// 设置 value: resource 资源信息
|
||||
super(getNameForResource(resource.getResource()), PropertiesLoaderUtils.loadProperties(resource));
|
||||
this.resourceName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a PropertySource having the given name based on Properties
|
||||
* loaded from the given encoded resource.
|
||||
*/
|
||||
public ResourcePropertySource(String name, Resource resource) throws IOException {
|
||||
super(name, PropertiesLoaderUtils.loadProperties(new EncodedResource(resource)));
|
||||
this.resourceName = getNameForResource(resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a PropertySource based on Properties loaded from the given resource.
|
||||
* The name of the PropertySource will be generated based on the
|
||||
* {@link Resource#getDescription() description} of the given resource.
|
||||
*/
|
||||
public ResourcePropertySource(Resource resource) throws IOException {
|
||||
super(getNameForResource(resource), PropertiesLoaderUtils.loadProperties(new EncodedResource(resource)));
|
||||
this.resourceName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a PropertySource having the given name based on Properties loaded from
|
||||
* the given resource location and using the given class loader to load the
|
||||
* resource (assuming it is prefixed with {@code classpath:}).
|
||||
*/
|
||||
public ResourcePropertySource(String name, String location, ClassLoader classLoader) throws IOException {
|
||||
// 默认资源读取器读取 location 转换成 resource
|
||||
this(name, new DefaultResourceLoader(classLoader).getResource(location));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a PropertySource based on Properties loaded from the given resource
|
||||
* location and use the given class loader to load the resource, assuming it is
|
||||
* prefixed with {@code classpath:}. The name of the PropertySource will be
|
||||
* generated based on the {@link Resource#getDescription() description} of the
|
||||
* resource.
|
||||
*/
|
||||
public ResourcePropertySource(String location, ClassLoader classLoader) throws IOException {
|
||||
this(new DefaultResourceLoader(classLoader).getResource(location));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a PropertySource having the given name based on Properties loaded from
|
||||
* the given resource location. The default thread context class loader will be
|
||||
* used to load the resource (assuming the location string is prefixed with
|
||||
* {@code classpath:}.
|
||||
*/
|
||||
public ResourcePropertySource(String name, String location) throws IOException {
|
||||
this(name, new DefaultResourceLoader().getResource(location));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a PropertySource based on Properties loaded from the given resource
|
||||
* location. The name of the PropertySource will be generated based on the
|
||||
* {@link Resource#getDescription() description} of the resource.
|
||||
*/
|
||||
public ResourcePropertySource(String location) throws IOException {
|
||||
this(new DefaultResourceLoader().getResource(location));
|
||||
}
|
||||
|
||||
private ResourcePropertySource(String name, @Nullable String resourceName, Map<String, Object> source) {
|
||||
super(name, source);
|
||||
this.resourceName = resourceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the description for the given Resource; if the description is
|
||||
* empty, return the class name of the resource plus its identity hash code.
|
||||
* @see org.springframework.core.io.Resource#getDescription()
|
||||
*/
|
||||
private static String getNameForResource(Resource resource) {
|
||||
// 获取 resource 的介绍
|
||||
String name = resource.getDescription();
|
||||
if (!StringUtils.hasText(name)) {
|
||||
// 短类名+@+hashcode
|
||||
name = resource.getClass().getSimpleName() + "@" + System.identityHashCode(resource);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a potentially adapted variant of this {@link ResourcePropertySource},
|
||||
* overriding the previously given (or derived) name with the specified name.
|
||||
* @since 4.0.4
|
||||
*/
|
||||
public ResourcePropertySource withName(String name) {
|
||||
if (this.name.equals(name)) {
|
||||
return this;
|
||||
}
|
||||
// Store the original resource name if necessary...
|
||||
if (this.resourceName != null) {
|
||||
if (this.resourceName.equals(name)) {
|
||||
return new ResourcePropertySource(this.resourceName, null, this.source);
|
||||
}
|
||||
else {
|
||||
return new ResourcePropertySource(name, this.resourceName, this.source);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Current name is resource name -> preserve it in the extra field...
|
||||
return new ResourcePropertySource(name, this.name, this.source);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a potentially adapted variant of this {@link ResourcePropertySource},
|
||||
* overriding the previously given name (if any) with the original resource name
|
||||
* (equivalent to the name generated by the name-less constructor variants).
|
||||
* @since 4.1
|
||||
*/
|
||||
public ResourcePropertySource withResourceName() {
|
||||
if (this.resourceName == null) {
|
||||
return this;
|
||||
}
|
||||
return new ResourcePropertySource(this.resourceName, null, this.source);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
@ -0,0 +1,36 @@
|
||||
# Spring ServletConfigPropertySource
|
||||
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- 类全路径: `org.springframework.web.context.support.ServletConfigPropertySource`
|
||||
- 内部数据结构是 `ServletConfig`
|
||||
|
||||
|
||||
- 整体代码如下
|
||||
|
||||
```java
|
||||
|
||||
public class ServletConfigPropertySource extends EnumerablePropertySource<ServletConfig> {
|
||||
|
||||
public ServletConfigPropertySource(String name, ServletConfig servletConfig) {
|
||||
super(name, servletConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getPropertyNames() {
|
||||
// javax.servlet.ServletConfig.getInitParameterNames
|
||||
return StringUtils.toStringArray(this.source.getInitParameterNames());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getProperty(String name) {
|
||||
// javax.servlet.ServletConfig.getInitParameter
|
||||
return this.source.getInitParameter(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
@ -0,0 +1,37 @@
|
||||
# Spring ServletContextPropertySource
|
||||
|
||||
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
- 类全路径: `org.springframework.web.context.support.ServletContextPropertySource`
|
||||
- 内部数据结构是 ServletContext 接口
|
||||
|
||||
- 整体代码如下.
|
||||
|
||||
|
||||
```java
|
||||
|
||||
public class ServletContextPropertySource extends EnumerablePropertySource<ServletContext> {
|
||||
|
||||
public ServletContextPropertySource(String name, ServletContext servletContext) {
|
||||
super(name, servletContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getPropertyNames() {
|
||||
// javax.servlet.ServletContext.getInitParameterNames 方法调用
|
||||
return StringUtils.toStringArray(this.source.getInitParameterNames());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getProperty(String name) {
|
||||
// javax.servlet.ServletContext.getInitParameter
|
||||
return this.source.getInitParameter(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
@ -0,0 +1,55 @@
|
||||
# Spring SimpleCommandLineArgsParser
|
||||
|
||||
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
|
||||
- 类全路径: `org.springframework.core.env.SimpleCommandLineArgsParser
|
||||
- 类作用: 将命令行参数解析成 `org.springframework.core.env.CommandLineArgs`
|
||||
|
||||
- 完整代码如下.
|
||||
```java
|
||||
|
||||
class SimpleCommandLineArgsParser {
|
||||
|
||||
/**
|
||||
* Parse the given {@code String} array based on the rules described {@linkplain
|
||||
* SimpleCommandLineArgsParser above}, returning a fully-populated
|
||||
* {@link CommandLineArgs} object.
|
||||
* @param args command line arguments, typically from a {@code main()} method
|
||||
*/
|
||||
public CommandLineArgs parse(String... args) {
|
||||
CommandLineArgs commandLineArgs = new CommandLineArgs();
|
||||
for (String arg : args) {
|
||||
if (arg.startsWith("--")) {
|
||||
String optionText = arg.substring(2, arg.length());
|
||||
String optionName;
|
||||
String optionValue = null;
|
||||
if (optionText.contains("=")) {
|
||||
optionName = optionText.substring(0, optionText.indexOf('='));
|
||||
optionValue = optionText.substring(optionText.indexOf('=') + 1, optionText.length());
|
||||
}
|
||||
else {
|
||||
optionName = optionText;
|
||||
}
|
||||
if (optionName.isEmpty() || (optionValue != null && optionValue.isEmpty())) {
|
||||
throw new IllegalArgumentException("Invalid argument syntax: " + arg);
|
||||
}
|
||||
commandLineArgs.addOptionArg(optionName, optionValue);
|
||||
}
|
||||
else {
|
||||
commandLineArgs.addNonOptionArg(arg);
|
||||
}
|
||||
}
|
||||
return commandLineArgs;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- 处理流程
|
||||
1. 循环命令行参数列表
|
||||
2. 去掉 `--` 和 `=` 获取参数名称和参数值放入结果集合
|
@ -0,0 +1,175 @@
|
||||
# Spring SimpleCommandLinePropertySource
|
||||
|
||||
- 全路径: `org.springframework.core.env.SimpleCommandLinePropertySource`
|
||||
|
||||
|
||||
|
||||
```java
|
||||
public class SimpleCommandLinePropertySource extends CommandLinePropertySource<CommandLineArgs> {}
|
||||
```
|
||||
|
||||
- SimpleCommandLinePropertySource 的source 类型是 CommandLineArgs 具体解释请看下面分析
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## CommandLineArgs
|
||||
|
||||
两个内部属性
|
||||
|
||||
```java
|
||||
class CommandLineArgs {
|
||||
/**
|
||||
* 选项参数列表
|
||||
*/
|
||||
private final Map<String, List<String>> optionArgs = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 非选项参数列表
|
||||
*/
|
||||
private final List<String> nonOptionArgs = new ArrayList<>();
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### addOptionArg
|
||||
|
||||
添加 选项参数
|
||||
|
||||
```java
|
||||
public void addOptionArg(String optionName, @Nullable String optionValue) {
|
||||
if (!this.optionArgs.containsKey(optionName)) {
|
||||
this.optionArgs.put(optionName, new ArrayList<>());
|
||||
}
|
||||
if (optionValue != null) {
|
||||
this.optionArgs.get(optionName).add(optionValue);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### getOptionNames
|
||||
|
||||
- 获取选项参数列表
|
||||
|
||||
```java
|
||||
public Set<String> getOptionNames() {
|
||||
return Collections.unmodifiableSet(this.optionArgs.keySet());
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- 其他方法不具体描述了,各位可以查看下面的代码
|
||||
|
||||
|
||||
|
||||
```java
|
||||
class CommandLineArgs {
|
||||
|
||||
/**
|
||||
* 选项参数列表
|
||||
*/
|
||||
private final Map<String, List<String>> optionArgs = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 非选项参数列表
|
||||
*/
|
||||
private final List<String> nonOptionArgs = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Add an option argument for the given option name and add the given value to the
|
||||
* list of values associated with this option (of which there may be zero or more).
|
||||
* The given value may be {@code null}, indicating that the option was specified
|
||||
* without an associated value (e.g. "--foo" vs. "--foo=bar").
|
||||
*
|
||||
* 添加 选项参数
|
||||
*/
|
||||
public void addOptionArg(String optionName, @Nullable String optionValue) {
|
||||
if (!this.optionArgs.containsKey(optionName)) {
|
||||
this.optionArgs.put(optionName, new ArrayList<>());
|
||||
}
|
||||
if (optionValue != null) {
|
||||
this.optionArgs.get(optionName).add(optionValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of all option arguments present on the command line.
|
||||
* 获取选项参数列表
|
||||
*/
|
||||
public Set<String> getOptionNames() {
|
||||
return Collections.unmodifiableSet(this.optionArgs.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the option with the given name was present on the command line.
|
||||
*/
|
||||
public boolean containsOption(String optionName) {
|
||||
return this.optionArgs.containsKey(optionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of values associated with the given option. {@code null} signifies
|
||||
* that the option was not present; empty list signifies that no values were associated
|
||||
* with this option.
|
||||
*/
|
||||
@Nullable
|
||||
public List<String> getOptionValues(String optionName) {
|
||||
return this.optionArgs.get(optionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given value to the list of non-option arguments.
|
||||
*/
|
||||
public void addNonOptionArg(String value) {
|
||||
this.nonOptionArgs.add(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of non-option arguments specified on the command line.
|
||||
*/
|
||||
public List<String> getNonOptionArgs() {
|
||||
return Collections.unmodifiableList(this.nonOptionArgs);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
在了解 CommandLineArgs 类后再来看 SimpleCommandLinePropertySource 会相对容易. 内部的几个方法就是调用 CommandLineArgs 所提供的方法
|
||||
|
||||
|
||||
|
||||
```java
|
||||
@Override
|
||||
public String[] getPropertyNames() {
|
||||
return StringUtils.toStringArray(this.source.getOptionNames());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean containsOption(String name) {
|
||||
return this.source.containsOption(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected List<String> getOptionValues(String name) {
|
||||
return this.source.getOptionValues(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getNonOptionArgs() {
|
||||
return this.source.getNonOptionArgs();
|
||||
}
|
||||
```
|
||||
|
@ -0,0 +1,28 @@
|
||||
# Spring StubPropertySource
|
||||
|
||||
- Author: [HuiFer](https://github.com/huifer)
|
||||
- 源码阅读仓库: [SourceHot-spring](https://github.com/SourceHot/spring-framework-read)
|
||||
|
||||
|
||||
|
||||
- 整体代码如下.
|
||||
- 通过 StubPropertySource 的 getProperty 方法永远返回null
|
||||
|
||||
```java
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
Loading…
Reference in new issue