1. 程式人生 > >Spring屬性源抽象PropertySource

Spring屬性源抽象PropertySource

概述

對於各種基於"名稱/值"對(key/value pair)的屬性源,Spring將其抽象成了抽象泛型類PropertySource<T>。底層的屬性源T可以是容納屬性資訊的任意型別,比如java.util.Properties,java.util.Map,ServletContext,ServletConfig物件,或者是命令列引數CommandLineArgs物件。類PropertySource的方法getSource()用於獲取底層的屬性源物件T。頂層的屬性源物件經過PropertySource封裝,從而具有統一的訪問方式。

以下是該抽象類的常用的一些具體實現類:

實現類 說明
RandomValuePropertySource 封裝一個random物件為屬性源,用於獲取int,long,uuid隨機數
MapPropertySource 封裝一個Map<String,Object>物件為屬性源
ServletConfigPropertySource 封裝一個ServletConfig物件為屬性源
ServletContextPropertySource
封裝一個ServletContext物件為屬性源
SystemEnvironmentPropertySource 繼承自MapPropertySource
StandardEnvironment用於將System.getenv()封裝成一個屬性源
在獲取屬性的屬性名上針對不同環境做了處理,比如getProperty("foo.bar")會匹配"foo.bar",“foo_bar”,“FOO.BAR"或者"FOO_BAR”,如果想獲取的屬性名稱中含有-,會被當作_處理。
SimpleCommandLinePropertySource
將命令列引數字串陣列轉換成一個CommandLineArgs物件,然後封裝成一個屬性源
比如一個springboot應用SpringApplication啟動時,如果提供了命令列引數,他們就會被封裝成一個SimpleCommandLinePropertySource物件放到上下文環境中去。
PropertiesPropertySource 繼承自MapPropertySource,將一個java.util.Properties物件封裝為屬性源

它們之間的繼承關係如下:
PropertySource及其實現類

注意這裡的EnumerablePropertySource抽象類,它為PropertySource增加了一個String[] getPropertyNames()方法,要求實現類提供,從而使相應的屬性源物件可以被列舉訪問所包含的各個屬性值對。

原始碼分析

// 僅分析核心抽象
package org.springframework.core.env;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

/**
 * Abstract base class representing a source of name/value property pairs. The underlying
 * #getSource() source object may be of any type T that encapsulates
 * properties. Examples include java.util.Properties objects, java.util.Map
 * objects, ServletContext and ServletConfig objects (for access to init
 * parameters). Explore the PropertySource type hierarchy to see provided
 * implementations.
 * 
 * 抽象基類,用於表示一個名稱/值屬性對的來源,簡稱為屬性源。底層的屬性源物件的型別通過泛型類T指定。
 *
 * PropertySource objects are not typically used in isolation, but rather
 * through a PropertySources object, which aggregates property sources and in
 * conjunction with a PropertyResolver implementation that can perform
 * precedence-based searches across the set of PropertySources.
 *
 * PropertySource 物件通常並不孤立使用,而是將多個PropertySource物件封裝成一個PropertySources
 * 物件來使用。另外還會有一個PropertyResolver屬性解析器工作在PropertySources物件上,基於特定的優先順序,
 * 來訪問這些屬性源物件中的屬性。
 * 
 * PropertySource identity is determined not based on the content of
 * encapsulated properties, but rather based on the #getName() name of the
 * PropertySource alone. This is useful for manipulating PropertySource
 * objects when in collection contexts. See operations in MutablePropertySources
 * as well as the #named(String) and #toString() methods for details.
 * PropertySource有一個唯一標識id,這個唯一標識id不是基於所封裝的屬性內容,而是基於指定給
 * 這個PropertySource物件的名稱屬性#getName()。
 *
 * Note that when working with
 * org.springframework.context.annotation.Configuration Configuration classes that
 * the @org.springframework.context.annotation.PropertySource PropertySource
 * annotation provides a convenient and declarative way of adding property sources to the
 * enclosing Environment.
 *
 * @author Chris Beams
 * @since 3.1
 * @param <T> the source type
 * @see PropertySources
 * @see PropertyResolver
 * @see PropertySourcesPropertyResolver
 * @see MutablePropertySources
 * @see org.springframework.context.annotation.PropertySource
 */
public abstract class PropertySource<T> {

	protected final Log logger = LogFactory.getLog(getClass());

	protected final String name;

	protected final T source;


	/**
	 * Create a new PropertySource with the given name and source object.
	 * 將某個T型別的底層屬性源source物件封裝成一個特定名稱為name的PropertySource物件
	 */
	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 PropertySource with the given name and with a new
	 * 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.
	 * 使用一個空物件構建一個指定名稱為name的PropertySource物件。通常用於測試目的。
	 */
	@SuppressWarnings("unchecked")
	public PropertySource(String name) {
		this(name, (T) new Object());
	}


	/**
	 * Return the name of this PropertySource.獲取屬性源名稱
	 */
	public String getName() {
		return this.name;
	}

	/**
	 * Return the underlying source object for this PropertySource.
	 * 獲取所封裝的底層屬性源物件,型別為泛型T。
	 */
	public T getSource() {
		return this.source;
	}

	/**
	 * Return whether this PropertySource contains the given name.
	 * This implementation simply checks for a null return value
	 * from #getProperty(String). Subclasses may wish to implement
	 * a more efficient algorithm if possible.
	 * 檢視指定名稱為name的屬性是否被當前PropertySource物件包含,
	 * 判斷方法:嘗試獲取該名稱的屬性值,如果值不為null認為是包含;否則認為是不包含。
	 * 繼承類可以提供不同的判斷方法和實現。
	 * @param name the property name to find
	 */
	public boolean containsProperty(String name) {
		return (getProperty(name) != null);
	}

	/**
	 * Return the value associated with the given name,
	 * or null if not found.
	 * 獲取指定名稱為name的屬性的值,如果該屬性不存在於該PropertySource物件,返回null
	 * @param name the property to find
	 * @see PropertyResolver#getRequiredProperty(String)
	 */
	@Nullable
	public abstract Object getProperty(String name);



}