Environment是當前應用運行環境的公開接口,主要包括應用程序運行環境的兩個關鍵方面:配置文件(profiles)和屬性(properties)。
- profiles:
profile配置是一個被命名的、bean定義的邏輯組,這些bean只有在給定的profile配置激活時纔會註冊到容器
- properties:
properties屬性可能來源於properties文件、JVM properties、system環境變量、JNDI、servlet context parameters上下文參數、專門的properties對象,Maps等等.
類圖
源碼解析
PropertyResolver
PropertyResolver提供屬性訪問功能,並能夠解析佔位符屬性(${...})。
public interface PropertyResolver {
boolean containsProperty(String key);
@Nullable
String getProperty(String key);
String getProperty(String key, String defaultValue);
@Nullable
<T> T getProperty(String key, Class<T> targetType);
<T> T getProperty(String key, Class<T> targetType, T defaultValue);
//如果不存在屬性值,則拋出異常
String getRequiredProperty(String key) throws IllegalStateException;
<T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException;
//解析佔位符
String resolvePlaceholders(String text);
String resolveRequiredPlaceholders(String text) throws IllegalArgumentException;
}
ConfigurablePropertyResolver
ConfigurablePropertyResolver,繼承自PropertyResolver,主要提供屬性類型轉換(基於org.springframework.core.convert.ConversionService)功能。
public interface ConfigurablePropertyResolver extends PropertyResolver {
ConfigurableConversionService getConversionService();
void setConversionService(ConfigurableConversionService conversionService);
void setPlaceholderPrefix(String placeholderPrefix);
void setPlaceholderSuffix(String placeholderSuffix);
void setValueSeparator(@Nullable String valueSeparator);
void setIgnoreUnresolvableNestedPlaceholders(boolean ignoreUnresolvableNestedPlaceholders);
void setRequiredProperties(String... requiredProperties);
void validateRequiredProperties() throws MissingRequiredPropertiesException;
}
Environment
Environment繼承自PropertyResolver,提供訪問和判斷profiles的功能。
public interface Environment extends PropertyResolver {
String[] getActiveProfiles();
String[] getDefaultProfiles();
@Deprecated
boolean acceptsProfiles(String... profiles);
//判斷profiles是否被激活
boolean acceptsProfiles(Profiles profiles);
}
ConfigurableEnvironment
ConfigurableEnvironment繼承自ConfigurablePropertyResolver和Environment,提供設置激活的profile和默認的profile的功能以及合併profiles,
public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {
void setActiveProfiles(String... profiles);
void addActiveProfile(String profile);
void setDefaultProfiles(String... profiles);
MutablePropertySources getPropertySources();
//返回System#getProperties()的值,應用了SecurityManager
Map<String, Object> getSystemProperties();
//返回System#getenv()的值,應用了SecurityManager
Map<String, Object> getSystemEnvironment();
void merge(ConfigurableEnvironment parent);
}
ConfigurableWebEnvironment
ConfigurableWebEnvironment繼承自ConfigurableEnvironment,並且提供配置Servlet上下文和Servlet參數的功能。
public interface ConfigurableWebEnvironment extends ConfigurableEnvironment {
void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig);
}
ConfigurableReactiveWebEnvironment
專爲reactive項目制定的ConfigurableEnvironment
public interface ConfigurableReactiveWebEnvironment extends ConfigurableEnvironment {
}
AbstractPropertyResolver
AbstractPropertyResolver是ConfigurablePropertyResolver接口的抽象實現類,提供了大部分接口方法的默認實現,將核心的getProperty(String key, Class<T> targetType)方法留給子類實現,resolvePlaceholders(String text)方法則由PropertyPlaceholderHelper提供默認實現。
屬性
//轉換服務
@Nullable
private volatile ConfigurableConversionService conversionService;
@Nullable
private PropertyPlaceholderHelper nonStrictHelper;
@Nullable
private PropertyPlaceholderHelper strictHelper;
private boolean ignoreUnresolvableNestedPlaceholders = false;
//佔位符前綴,默認:"${"
private String placeholderPrefix = SystemPropertyUtils.PLACEHOLDER_PREFIX;
//佔位符後綴,默認:"}"
private String placeholderSuffix = SystemPropertyUtils.PLACEHOLDER_SUFFIX;
//默認值分隔符,默認:":"
@Nullable
private String valueSeparator = SystemPropertyUtils.VALUE_SEPARATOR;
//必需屬性
private final Set<String> requiredProperties = new LinkedHashSet<>();
conversionService
轉換服務是轉換器(Converter)的容器(ConverterRegistry)。
public interface ConverterRegistry {
void addConverter(Converter<?, ?> converter);
<S, T> void addConverter(Class<S> sourceType, Class<T> targetType, Converter<? super S, ? extends T> converter);
void addConverter(GenericConverter converter);
void addConverterFactory(ConverterFactory<?, ?> factory);
void removeConvertible(Class<?> sourceType, Class<?> targetType);
}
如果沒有設置,默認使用:DefaultConversionService
解析佔位符
private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
return helper.replacePlaceholders(text, this::getPropertyAsRawString);
}
獲取原始值,再替換佔位符。
PropertyPlaceholderHelper
public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
Assert.notNull(value, "'value' must not be null");
return parseStringValue(value, placeholderResolver, null);
}
parseStringValue遞歸解析佔位符。遇到${開頭就會查找最後一個}符號,將最外層佔位符內的內容作爲新的value再次傳入 parseStringValue()方法中,這樣最深層次也就是最先返回的就是最裏層的佔位符名字。調用placeholderResolver將佔位符名字轉換成它代表的值。如果值爲null,則考慮使用默認值(valueSeparator後的內容)賦值給propVal。由於placeholderResolver轉換過的值有可能還會包含佔位符所以在此調用parseStringValue()方法將帶有佔位符的propVal傳入返回真正的值,用propVal替換佔位符。如果propVal==null,判斷是否允許忽略不能解析的佔位符,如果可以重置startIndex繼續解析同一層次的佔位符。否則拋出異常。這個函數的返回值就是它上一層次的佔位符解析值。
需要注意的一點是:判斷嵌套的佔位符是依據simplePrefix。
PropertySourcesPropertyResolver
PropertySourcesPropertyResolver是體系中唯一的完整實現類。它以PropertySources屬性源集合(內部持有屬性源列表List<PropertySource>)爲屬性值的來源,按序遍歷每個PropertySource,獲取到一個非null的屬性值則返回。
protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
if (this.propertySources != null) {
for (PropertySource<?> propertySource : this.propertySources) {
......
Object value = propertySource.getProperty(key);
if (value != null) {
if (resolveNestedPlaceholders && value instanceof String) {
value = resolveNestedPlaceholders((String) value);
}
logKeyFound(key, propertySource, value);
return convertValueIfNecessary(value, targetValueType);
}
}
}
return null;
}
protected String getPropertyAsRawString(String key) {
return getProperty(key, String.class, false);
}
AbstractEnvironment
屬性
//是否忽略系統環境(System#getenv())的屬性名稱
public static final String IGNORE_GETENV_PROPERTY_NAME = "spring.getenv.ignore";
//激活的profiles的屬性名稱(屬性值以逗號分隔)
public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.profiles.active";
//激活的profiles的屬性名稱(屬性值以逗號分隔)
public static final String DEFAULT_PROFILES_PROPERTY_NAME = "spring.profiles.default";
//默認profile的名稱:default
protected static final String RESERVED_DEFAULT_PROFILE_NAME = "default";
//激活的profiles
private final Set<String> activeProfiles = new LinkedHashSet<>();
//默認的profiles
private final Set<String> defaultProfiles = new LinkedHashSet<>(getReservedDefaultProfiles());
//propertySources
private final MutablePropertySources propertySources = new MutablePropertySources();
private final ConfigurablePropertyResolver propertyResolver =
new PropertySourcesPropertyResolver(this.propertySources);
由子類設置PropertySource
protected void customizePropertySources(MutablePropertySources propertySources) {
}
獲取profiles
protected Set<String> doGetActiveProfiles() {
synchronized (this.activeProfiles) {
if (this.activeProfiles.isEmpty()) {
String profiles = getProperty(ACTIVE_PROFILES_PROPERTY_NAME);
if (StringUtils.hasText(profiles)) {
setActiveProfiles(StringUtils.commaDelimitedListToStringArray(
StringUtils.trimAllWhitespace(profiles)));
}
}
return this.activeProfiles;
}
}
StandardEnvironment
StandardEnvironment繼承自AbstractEnvironment,非Servlet(Web)環境下的標準Environment實現。提供系統屬性以及系統環境變量的獲取。
public class StandardEnvironment extends AbstractEnvironment {
/** System environment property source name: {@value}. */
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
/** JVM system properties property source name: {@value}. */
public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(
new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
propertySources.addLast(
new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}
}
StandardServletEnvironment
StandardServletEnvironment繼承自StandardEnvironment,Servlet(Web)環境下的標準Environment實現。
public class StandardServletEnvironment extends StandardEnvironment implements ConfigurableWebEnvironment {
/** Servlet context init parameters property source name: {@value}. */
public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";
/** Servlet config init parameters property source name: {@value}. */
public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams";
/** JNDI property source name: {@value}. */
public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties";
@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
}
super.customizePropertySources(propertySources);
}
@Override
public void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
WebApplicationContextUtils.initServletPropertySources(getPropertySources(), servletContext, servletConfig);
}
}
StandardReactiveWebEnvironment
用於reactive web 應用。
public class StandardReactiveWebEnvironment extends StandardEnvironment implements ConfigurableReactiveWebEnvironment {
}
MutablePropertySources
提供PropertySource的容器。內部存儲爲CopyOnWriteArrayList。
PropertySource
PropertySource 類 設計用來存放<key,value>對象的抽象類。同時name,source都是final在初始化後不在變化。
PropertySource的最常用子類是MapPropertySource、PropertiesPropertySource、ResourcePropertySource、StubPropertySource、ComparisonPropertySource:
- MapPropertySource:source指定爲Map實例的PropertySource實現。
- PropertiesPropertySource:source指定爲Map實例的PropertySource實現,內部的Map實例由Properties實例轉換而來。
- ResourcePropertySource:繼承自PropertiesPropertySource,source指定爲通過Resource實例轉化爲Properties再轉換爲Map實例。
- StubPropertySource:PropertySource的一個內部類,source設置爲null,實際上就是空實現。
- ComparisonPropertySource:所有屬性訪問方法強制拋出異常,作用就是一個不可訪問屬性的空實現。
public abstract class PropertySource<T> {
protected final String name;
protected final T source;
public boolean equals(@Nullable Object other) {
return (this == other || (other instanceof PropertySource &&
ObjectUtils.nullSafeEquals(this.name, ((PropertySource<?>) other).name)));
}
public int hashCode() {
return ObjectUtils.nullSafeHashCode(this.name);
}
}
SpringBoot啓動
在Spring boot 啓動時,會準備環境Environment,在Environment準備好之後,會廣播一個ApplicationEnvironmentPreparedEvent:調用各listener的environmentPrepared(ConfigurableEnvironment environment)方法,
listeners.environmentPrepared(environment);
void environmentPrepared(ConfigurableEnvironment environment) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.environmentPrepared(environment);
}
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster
.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}
此時獲取到的事件監聽器包括:ConfigFileApplicationListener 等
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
}
if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent(event);
}
}
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
postProcessors.add(this);
AnnotationAwareOrderComparator.sort(postProcessors);
for (EnvironmentPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
}
}
List<EnvironmentPostProcessor> loadPostProcessors() {
return SpringFactoriesLoader.loadFactories(EnvironmentPostProcessor.class, getClass().getClassLoader());
}
在onApplicationEnvironmentPreparedEvent()方法中,會處理EnvironmentPostProcessor,默認4個:
# Environment Post Processors org.springframework.boot.env.EnvironmentPostProcessor=\ org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\ org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\ org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\ org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor
同時ConfigFileApplicationListener 繼承EnvironmentPostProcessor,postProcessEnvironment()實現如下:
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
addPropertySources(environment, application.getResourceLoader());
}
protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
RandomValuePropertySource.addToEnvironment(environment);
new Loader(environment, resourceLoader).load();
}
會使用封裝的Loader加載配置
Loader
Loader類是ConfigFileApplicationListener 的一個內部類,用於加載配置。
屬性
private class Loader {
//環境信息
private final ConfigurableEnvironment environment;
//佔位符解析器
private final PropertySourcesPlaceholdersResolver placeholdersResolver;
//資源加載器
//private final ResourceLoader resourceLoader;
屬性加載器
private final List<PropertySourceLoader> propertySourceLoaders;
//profile
private Deque<Profile> profiles;
//處理的profile
private List<Profile> processedProfiles;
private boolean activatedProfiles;
//已加載的配置
private Map<Profile, MutablePropertySources> loaded;
private Map<DocumentsCacheKey, List<Document>> loadDocumentsCache = new HashMap<>();
}
初始化
Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
this.environment = environment;
//構造PlaceholdersResolver
this.placeholdersResolver = new PropertySourcesPlaceholdersResolver(this.environment);
this.resourceLoader = (resourceLoader != null) ? resourceLoader : new DefaultResourceLoader();
//從factories中加載類
this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class,
getClass().getClassLoader());
}
# PropertySource Loaders org.springframework.boot.env.PropertySourceLoader=\ org.springframework.boot.env.PropertiesPropertySourceLoader,\ org.springframework.boot.env.YamlPropertySourceLoader
使用
Properties
properties配置文件
<context:property-placeholder location="classpath:db.properties" />
註解方式
@Configuration
@PropertySource("classpath:db.properties")
public class TestProperties {
@Autowired
Environment env;
public void getProperty() {
environment.getProperty("jdbc.driverClassName");
}
}
Profiles
配置
<beans profile="test">
<context:property-placeholder location="/WEB-INF/test.properties" />
</beans>
<beans profile="beta">
<context:property-placeholder location="/WEB-INF/beta.properties" />
</beans>
激活
- 代碼指定
ConfigurableEnvironment.setActiveProfiles("test")
- 配置文件指定
<init-param>
<param-name>spring.profiles.active</param-name>
<param-value>beta</param-value>
</init-param>
- 啓動參數指定
JAVA_OPTS="-Dspring.profiles.active=test"
Enviorment
引用
- Autoware
@Autowired
private Environment environment;
- 實現EnvironmentAware接口