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接口