介绍
Environment是spring中配置文件数据的载体,对外暴露使用的配置文件名称,如:profiles.active,这样我们就可以知道在使用哪个配置文件的信息了。
ConfigurableEnvironment继承于Environment,并且ConfigurableEnvironment还继承了ConfigurablePropertyResolver,而ConfigurablePropertyResolver继承于PropertyResolver。
对于PropertyResolver上一章已经说了,它是对于键值属性PropertySource对外数据的统一处理。实现它来获取PropertySource的数据。
所以ConfigurableEnvironment不仅提供了配置文件解析的数据,以及配置文件名称,还提供了PropertySource数据。其实配置文件的解析出来的数据,也是封装成了PropertySource放在ConfigurableEnvironment中。
接下来看看ConfigurableEnvironment的接口以及实现吧
ConfigurableEnvironment
public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {
//设置活动的配置文件
void setActiveProfiles(String... profiles);
// 增加活动的配置文件
void addActiveProfile(String profile);
// 设置默认的配置文件
void setDefaultProfiles(String... profiles);
// 获取PropertySource键值组合的集合
MutablePropertySources getPropertySources();
// 系统环境变量
Map<String, Object> getSystemEnvironment();
// 系统配置
Map<String, Object> getSystemProperties();
// 合并
void merge(ConfigurableEnvironment parent);
}
ConfigurableEnvironment只是接口,接下来看看具体实现AbstractEnvironment。
AbstractEnvironment
public abstract class AbstractEnvironment implements ConfigurableEnvironment {
public static final String IGNORE_GETENV_PROPERTY_NAME = "spring.getenv.ignore";
public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.profiles.active";
public static final String DEFAULT_PROFILES_PROPERTY_NAME = "spring.profiles.default";
protected static final String RESERVED_DEFAULT_PROFILE_NAME = "default";
protected final Log logger = LogFactory.getLog(getClass());
private final Set<String> activeProfiles = new LinkedHashSet<String>();
private final Set<String> defaultProfiles = new LinkedHashSet<String>(getReservedDefaultProfiles());
private final MutablePropertySources propertySources = new MutablePropertySources(this.logger);
private final ConfigurablePropertyResolver propertyResolver =
new PropertySourcesPropertyResolver(this.propertySources);
public AbstractEnvironment() {
customizePropertySources(this.propertySources);
if (logger.isDebugEnabled()) {
logger.debug("Initialized " + getClass().getSimpleName() + " with PropertySources " + this.propertySources);
}
}
// 自定义PropertySource, 交给子类去实现
protected void customizePropertySources(MutablePropertySources propertySources) {
}
protected Set<String> getReservedDefaultProfiles() {
return Collections.singleton(RESERVED_DEFAULT_PROFILE_NAME);
}
@Override
public String[] getActiveProfiles() {
return StringUtils.toStringArray(doGetActiveProfiles());
}
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;
}
}
@Override
public String getProperty(String key) {
return this.propertyResolver.getProperty(key);
}
@Override
public String getProperty(String key, String defaultValue) {
return this.propertyResolver.getProperty(key, defaultValue);
}
@Override
public <T> T getProperty(String key, Class<T> targetType) {
return this.propertyResolver.getProperty(key, targetType);
}
@Override
public <T> T getProperty(String key, Class<T> targetType, T defaultValue) {
return this.propertyResolver.getProperty(key, targetType, defaultValue);
}
@Override
@Deprecated
public <T> Class<T> getPropertyAsClass(String key, Class<T> targetType) {
return this.propertyResolver.getPropertyAsClass(key, targetType);
}
@Override
public String getRequiredProperty(String key) throws IllegalStateException {
return this.propertyResolver.getRequiredProperty(key);
}
@Override
public <T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException {
return this.propertyResolver.getRequiredProperty(key, targetType);
}
@Override
public String resolvePlaceholders(String text) {
return this.propertyResolver.resolvePlaceholders(text);
}
@Override
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
return this.propertyResolver.resolveRequiredPlaceholders(text);
}
}
由于代码很长,就简单说几个方法,大部分都差不多,都是委托在propertyResolver在处理,由于propertyResolver上一章我们已经说过,所以就简单说下。
在AbstractEnvironment中,有个重要的属性就是MutablePropertySources。
它是PropertySource的集合,一般我们使用PropertySource时候也都是使用PropertySources接口,是PropertySource的集合的接口,继承了Iterable。这属于一种迭代器模式,我们不需要知道内部集合到底是什么数据类型,只知道实现了Iterable接口可以供for循环使用。就简单看下MutablePropertySources源码,很简单。就是内部定义了一个List<PropertySource>的属性,然后对这个list进行处理并且实现Iterable。
public class MutablePropertySources implements PropertySources {
private final Log logger;
private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<PropertySource<?>>();
public MutablePropertySources() {
this.logger = LogFactory.getLog(getClass());
}
public MutablePropertySources(PropertySources propertySources) {
this();
for (PropertySource<?> propertySource : propertySources) {
addLast(propertySource);
}
}
MutablePropertySources(Log logger) {
this.logger = logger;
}
@Override
public boolean contains(String name) {
return this.propertySourceList.contains(PropertySource.named(name));
}
@Override
public PropertySource<?> get(String name) {
int index = this.propertySourceList.indexOf(PropertySource.named(name));
return (index != -1 ? this.propertySourceList.get(index) : null);
}
@Override
public Iterator<PropertySource<?>> iterator() {
return this.propertySourceList.iterator();
}
public void addFirst(PropertySource<?> propertySource) {
if (logger.isDebugEnabled()) {
logger.debug("Adding PropertySource '" + propertySource.getName() + "' with highest search precedence");
}
removeIfPresent(propertySource);
this.propertySourceList.add(0, propertySource);
}
public void addLast(PropertySource<?> propertySource) {
if (logger.isDebugEnabled()) {
logger.debug("Adding PropertySource '" + propertySource.getName() + "' with lowest search precedence");
}
removeIfPresent(propertySource);
this.propertySourceList.add(propertySource);
}
public void addBefore(String relativePropertySourceName, PropertySource<?> propertySource) {
if (logger.isDebugEnabled()) {
logger.debug("Adding PropertySource '" + propertySource.getName() +
"' with search precedence immediately higher than '" + relativePropertySourceName + "'");
}
assertLegalRelativeAddition(relativePropertySourceName, propertySource);
removeIfPresent(propertySource);
int index = assertPresentAndGetIndex(relativePropertySourceName);
addAtIndex(index, propertySource);
}
public void addAfter(String relativePropertySourceName, PropertySource<?> propertySource) {
if (logger.isDebugEnabled()) {
logger.debug("Adding PropertySource '" + propertySource.getName() +
"' with search precedence immediately lower than '" + relativePropertySourceName + "'");
}
assertLegalRelativeAddition(relativePropertySourceName, propertySource);
removeIfPresent(propertySource);
int index = assertPresentAndGetIndex(relativePropertySourceName);
addAtIndex(index + 1, propertySource);
}
public int precedenceOf(PropertySource<?> propertySource) {
return this.propertySourceList.indexOf(propertySource);
}
public PropertySource<?> remove(String name) {
if (logger.isDebugEnabled()) {
logger.debug("Removing PropertySource '" + name + "'");
}
int index = this.propertySourceList.indexOf(PropertySource.named(name));
return (index != -1 ? this.propertySourceList.remove(index) : null);
}
public void replace(String name, PropertySource<?> propertySource) {
if (logger.isDebugEnabled()) {
logger.debug("Replacing PropertySource '" + name + "' with '" + propertySource.getName() + "'");
}
int index = assertPresentAndGetIndex(name);
this.propertySourceList.set(index, propertySource);
}
public int size() {
return this.propertySourceList.size();
}
@Override
public String toString() {
return this.propertySourceList.toString();
}
protected void assertLegalRelativeAddition(String relativePropertySourceName, PropertySource<?> propertySource) {
String newPropertySourceName = propertySource.getName();
if (relativePropertySourceName.equals(newPropertySourceName)) {
throw new IllegalArgumentException(
"PropertySource named '" + newPropertySourceName + "' cannot be added relative to itself");
}
}
protected void removeIfPresent(PropertySource<?> propertySource) {
this.propertySourceList.remove(propertySource);
}
private void addAtIndex(int index, PropertySource<?> propertySource) {
removeIfPresent(propertySource);
this.propertySourceList.add(index, propertySource);
}
private int assertPresentAndGetIndex(String name) {
int index = this.propertySourceList.indexOf(PropertySource.named(name));
if (index == -1) {
throw new IllegalArgumentException("PropertySource named '" + name + "' does not exist");
}
return index;
}
}
看到这里基本就基本明白了,AbstractEnvironment数据都是存储在MutablePropertySources中的,然后对于数据的处理都交给了ConfigurablePropertyResolver。
ConfigurablePropertyResolver上一章也说过了是PropertySource数据对外暴露的统一处理接口,并且提供了类型转换功能。
总结
ConfigurableEnvironment是spring中非常重要的角色,可以通过它获得activeProfiles,来判断我们所使用的环境是dev还是test或者prod等等。还可以根据getProperty拿到配置中的信息并且提供类型转换功能,以及获取系统环境变量等信息。