doc: PropertySource

pull/70/head
huifer 4 years ago
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…
Cancel
Save