Spring Environment

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 继承EnvironmentPostProcessorpostProcessEnvironment()实现如下:

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

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章