Environment

在这里插入图片描述

源码

/**
 * @author Chris Beams
 * @since 3.1
 * @see PropertyResolver
 * @see EnvironmentCapable
 * @see ConfigurableEnvironment
 * @see AbstractEnvironment
 * @see StandardEnvironment
 * @see org.springframework.context.EnvironmentAware
 * @see org.springframework.context.ConfigurableApplicationContext#getEnvironment
 * @see org.springframework.context.ConfigurableApplicationContext#setEnvironment
 * @see org.springframework.context.support.AbstractApplicationContext#createEnvironment
 */
public interface Environment extends PropertyResolver {
	
	String[] getActiveProfiles();

	String[] getDefaultProfiles();

	@Deprecated
	boolean acceptsProfiles(String... profiles);

	boolean acceptsProfiles(Profiles profiles);

}

据类上注释:
一,接口表示当前应用程序运行的环境。两个关键配置为:profiles和properties配置文件。属性访问通过PropertyResolver接口中相关的方法。所谓的profiles就类似于@Profile(“dev”)或者properties配置文件中的spring.profiles.active=dev。Environment通过getActiveProfiles知道当前激活那些配置文件,通过getDefaultProfiles知道那些被默认激活。
二,在ApplicationContext中管理的bean可以
1. 注册为EnvironmentAware,这里我理解为继承EnvironmentAware接口,并且实现其setEnvironment方法; EnvironmentAware详细说明
2. 通过@Inject 或者@Autowired注解 注入Environment;@Inject详细说明
这可以让我们直接访问Environment,然后访问配置文件中的内容
三,然而,在大多数情况下,应用程序级bean不需要与直接Environment交互而是使用占位符${…} 访问,这是通过PropertySourcesPlaceholderConfigurer 实现的,它本身是EnvironmentAware,并且在纯Spring 3.1之后在使用context:property-placeholder/时默认注册,而在springboot会默认注册。
四,Environment的配置必须通过ConfigurableEnvironment接口,该接口从所有AbstractApplicationContext的getEnvironment方法返回。

然后介绍相关类

PropertyResolver

Environment继承了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;

}

这些方法很简单,就是用来 获取属性。

EnvironmentCapable

public interface EnvironmentCapable {

	/**
	 * Return the {@link Environment} associated with this component.
	 */
	Environment getEnvironment();

}

显然,这个接口只有一个方法;

所有Spring应用程序上下文继承了EnvironmentCapable,接口主要用于在框架方法中执行instanceof检查,以便与环境交互(如果环境确实可用的话)。(注意ApplicationContext继承了ListableBeanFactory,而ListableBeanFactory继承了BeanFactory,但是继承了BeanFactory的未必是ApplicationContext,而继承EnvironmentCapable的一定是ApplicationContext)

ApplicationContext继承了EnvironmentCapable,从而继承了getenenvironment()方法; ConfigurableApplicationContext继承了ApplicationContext并重新定义了getEnvironment并缩小签名以返回一个ConfigurableEnvironment而非其父接口Environment。从ConfigurableApplicationContext访问Environment对象时,它都是“只读”的,此时它也可以被配置。(这个只读我不是很理解)

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);
 
}
  1. 由大多数Environment类型实现的配置接口,也就是说,一般而言,不会直接继承Environment,而是继承ConfigurableEnvironment
  2. 可以设置活动的和默认活动的profiles文件(如setActiveProfiles和setDefaultProfiles)
  3. 可以操作底层属性源。配置文件的解析出来的数据,也是封装成了PropertySource放在ConfigurableEnvironment中。
  4. 允许客户端通过ConfigurablePropertyResolver接口设置(setRequiredProperties)和验证(validateRequiredProperties)所需的属性,自定义转换服务(setConversionService)等。
操作属性源:
5. 属性源可以被删除、重新排序或替换;并且可以使用从getPropertySources返回的MutablePropertySources实例添加其他属性源。
6. 下面的示例是针对ConfigurableEnvironmentStandardEnvironment实现的,但一般适用于任何实现,尽管特定的默认属性源可能不同。
	1. 添加具有最高搜索优先级的新属性源:
	ConfigurableEnvironment environment = new StandardEnvironment();
	MutablePropertySources propertySources = environment.getPropertySources();
	Map<zString,String> myMap = new HashMap();
	myMap.put("xyz", "myValue");
	propertySources.addFirst(new MapPropertySource("MY_MAP", myMap));
	2. 删除默认的系统属性属性源
	MutablePropertySources propertySources = environment.getPropertySources();
	propertySources.remove(StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)
	3. 模拟系统环境以进行测试
	MutablePropertySources propertySources = environment.getPropertySources();
    MockPropertySource mockEnvVars = new MockPropertySource().withProperty("xyz", "myValue");
    propertySources.replace(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, mockEnvVars);

当ApplicationContext使用Environment时,在调用refresh方法(源自AbstractApplicationContext)之前执行此类PropertySource操作是很重要的。这确保了容器引导过程中所有属性源都是可用的,包括PropertySourcesPlaceholderConfigurer所使用的属性源。

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);
	}
	
    // 自定义PropertySource, 交给子类去实现
	protected void customizePropertySources(MutablePropertySources propertySources) {
	}
 
}
  1. 支持保留默认配置文件名称的概念,并支持通过ACTIVE_PROFILES_PROPERTY_NAME和DEFAULT_PROFILES_PROPERTY_NAME属性指定活动的和默认活动的配置文件。
  2. 具体子类的区别主要在于AbstractEnvironment默认添加PropertySource对象(在无参构造中)。不过这个交给子类实现
  3. 子类应该通过受保护的customizePropertySources(MutablePropertySources)钩子提供属性源也就是MutablePropertySources ,而客户端应该使用继承自ConfigurableEnvironment的getPropertySources()方法进行定制,并使用MutablePropertySources API。具体示例看上一小结

StandardEnvironment

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()));
	}

}
  1. 除了ConfigurableEnvironment的常用功能之外,增加了属性解析和配置文件相关的操作。
  2. 配置了两个默认属性源,按以下顺序搜索:getSystemProperties getSystemEnvironment(继承自AbstractEnvironment),也就是说,如果键“xyz”在JVM系统属性和当前进程的环境变量集中都存在,那么调用{environment. getproperty(“xyz”)}返回的是系统属性中的键“xyz”的值。
    这种顺序是默认选择的,因为系统属性是每个jvm的,而在给定系统上的许多jvm上的环境变量可能是相同的。给予系统属性优先级允许在每个jvm的基础上覆盖环境变量。如下面的代码
  3. 这些默认属性源可以被删除、重新排序或替换;
  4. 其他属性源可以使用可从getPropertySources() 获得的MutablePropertySources实例添加
  5. 有关特殊处理的详细信息,请参阅SystemEnvironmentPropertySource javadoc
    在shell环境中不允许在变量名中使用句点字符的属性名(例如Bash)
@RestController
public class EnvironmentController {

    @Autowired
    Environment environment;

    @GetMapping("testEnvironment")
    public String test(){
        System.setProperty("server.servlet.context-path","/Second");
        System.out.println(environment.resolvePlaceholders("${server.servlet.context-path}"));
        return environment.getProperty("server.servlet.context-path");
    }
}

返回的是/Second而不是/First

EnvironmentAware

public interface EnvironmentAware extends Aware {

	void setEnvironment(Environment environment);

}

接口被一些bean实现。setEnvironment方法在ConfigurableApplicationContext接口中也自定义了

ApplicationContext

所有的ApplicationContext都继承了EnvironmentCapable,所以都有getEnvironment方法
在ConfigurableApplicationContext中

	//自定义,非继承
	void setEnvironment(ConfigurableEnvironment environment);

	@Override
	ConfigurableEnvironment getEnvironment();

在AbstractApplicationContext中

	@Override
	public void setEnvironment(ConfigurableEnvironment environment) {
		this.environment = environment;
	}

	@Override
	public ConfigurableEnvironment getEnvironment() {
		if (this.environment == null) {
			this.environment = createEnvironment();
		}
		return this.environment;
	}

	//自定义,非继承
	protected ConfigurableEnvironment createEnvironment() {
		return new StandardEnvironment();
	}
	

显然,系统中默认的Environment是StandardEnvironment;如果要详细了解AbstractApplicationContext 或者 ConfigurableApplicationContext,请看ApplicationContext

StandardEnvironment

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";
	//实现了AbstractEnvironment 中的方法,是自定义属性源 添加属性到propertySources
	@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()));
	}

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值