Spring中的Environment

Environment

Environment表示应用当前所运行的环境。

Interface representing the environment in which the current application is running. Models two key aspects of the application
environment: profiles and properties. Methods related to property access are exposed via the PropertyResolver superinterface.

A profile is a named, logical group of bean definitions to be registered with the container only if the given profile is active. Beans may be assigned to a profile whether defined in XML or via annotations; see the spring-beans 3.1 schema or the @Profile annotation for syntax details. The role of the Environment object with relation to profiles is in determining which profiles (if any) are currently active, and which profiles (if any) should be active by default.

Properties play an important role in almost all applications, and may originate from a variety of sources: properties files, JVM system properties, system environment variables, JNDI, servlet context parameters, ad-hoc Properties objects, Maps, and so on. The role of the environment object with relation to properties is to provide the user with a convenient service interface for configuring property sources and resolving properties from them

Environment注释上可以看到,Environment主要负责处理两个方面:profilesproperties

profiles类似Maven中的profiles,Spring允许配置多个profile,但只加载激活的profile,通过profiles配置,可以实现不同环境使用不同的配置(例如不同环境使用不同的数据库配置)

properties在整个应用中都会用到,Spring会从各种来源加载:properties文件(例如数据库配置文件),JVM系统配置,系统环境变量,Servlet上下文参数等。通过properties,可以更加便捷的获取到配置信息

StandardEnvironment

StandardEnvironment

Environment

Environment定义了Profiles相关的方法:

1
2
3
4
5
6
7
8
9
10
11
12
public interface Environment extends PropertyResolver {

// 获取所有可用的`profile`,如果没有可用的,使用默认的`default`(因此可以在xml中配置默认的`profile`,名称为`default`)
String[] getActiveProfiles();

// 获取默认的`profile`,如果没有指定,返回默认的`default`
String[] getDefaultProfiles();

// 判断`profile`是否可用,可以使用'!'前缀作为取反标记
boolean acceptsProfiles(String... profiles);

}

ConfigurableEnvironment

如果说Environment定义了Profiles查询方法,那么ConfigurableEnvironment就定义了设置方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {

// 设置可用的`profile`
void setActiveProfiles(String... profiles);

// 添加可用的`profile`
void addActiveProfile(String profile);

// 设置默认的`profile`
void setDefaultProfiles(String... profiles);

// 获取`propertySources`
MutablePropertySources getPropertySources();

// 获取JVM系统配置
Map<String, Object> getSystemEnvironment();

// 获取系统配置
Map<String, Object> getSystemProperties();

// 合并`Environment`
void merge(ConfigurableEnvironment parent);
}

AbstractEnvironment

AbstractEnvironment对接口做了默认实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
public abstract class AbstractEnvironment implements ConfigurableEnvironment {

// 文件配置:是否忽略获取系统属性
public static final String IGNORE_GETENV_PROPERTY_NAME = "spring.getenv.ignore";

// 启动命令:指定使用的`profile`
public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.profiles.active";

// 启动命令:指定默认的`profile`
public static final String DEFAULT_PROFILES_PROPERTY_NAME = "spring.profiles.default";

// 默认`profile`名称。可以在将`profile`名称指定为`default`,`Spring`默认使用
protected static final String RESERVED_DEFAULT_PROFILE_NAME = "default";

protected final Log logger = LogFactory.getLog(getClass());

// 可用的`profile`列表
private final Set<String> activeProfiles = new LinkedHashSet<String>();

// 默认的`profile`列表,包含默认名称`default`,子类可覆盖`getReservedDefaultProfiles`,修改默认`profile`名称
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() {
// 自定义`propertySource`,子类实现。初始化时默认加载
customizePropertySources(this.propertySources);
if (this.logger.isDebugEnabled()) {
this.logger.debug(String.format(
"Initialized %s with PropertySources %s", getClass().getSimpleName(), this.propertySources));
}
}

// 由于`propertySource`在`propertySources`存在优先级(按顺序使用),子类覆盖需要注意,可以看方法原注释
protected void customizePropertySources(MutablePropertySources propertySources) {
}

// 默认`profile`列表,包含`default`的集合,子类可覆盖实现
protected Set<String> getReservedDefaultProfiles() {
return Collections.singleton(RESERVED_DEFAULT_PROFILE_NAME);
}

//---------------------------------------------------------------------
// Implementation of ConfigurableEnvironment interface
//---------------------------------------------------------------------

@Override
public String[] getActiveProfiles() {
return StringUtils.toStringArray(doGetActiveProfiles());
}

// 获取可用的`profile`集合
// 如果未设置可用的`profile`,解析启动参数`spring.profiles.active`,如果存在,设置为可用的`profile`
protected Set<String> doGetActiveProfiles() {
synchronized (this.activeProfiles) {
if (this.activeProfiles.isEmpty()) {
// 从启动参数`spring.profiles.active`获取`profile`
String profiles = getProperty(ACTIVE_PROFILES_PROPERTY_NAME);
if (StringUtils.hasText(profiles)) {
// 设置为可用的`profile`
setActiveProfiles(StringUtils.commaDelimitedListToStringArray(
StringUtils.trimAllWhitespace(profiles)));
}
}
return this.activeProfiles;
}
}

@Override
public void setActiveProfiles(String... profiles) {
Assert.notNull(profiles, "Profile array must not be null");
synchronized (this.activeProfiles) {
// 清空
this.activeProfiles.clear();
for (String profile : profiles) {
// 验证`profile`格式是否正确
validateProfile(profile);
// 添加为可用`profile`
this.activeProfiles.add(profile);
}
}
}

@Override
public void addActiveProfile(String profile) {
if (this.logger.isDebugEnabled()) {
this.logger.debug(String.format("Activating profile '%s'", profile));
}
// 验证`profile`格式是否正确
validateProfile(profile);
// 获取可用的`profile`集合,并添加
doGetActiveProfiles();
synchronized (this.activeProfiles) {
this.activeProfiles.add(profile);
}
}


@Override
public String[] getDefaultProfiles() {
return StringUtils.toStringArray(doGetDefaultProfiles());
}

// 获取默认的`profile`集合
// 如果未设置默认的`profile`,解析启动参数`spring.profiles.default`,如果存在,设置为默认的`profile`
protected Set<String> doGetDefaultProfiles() {
synchronized (this.defaultProfiles) {
if (this.defaultProfiles.equals(getReservedDefaultProfiles())) {
// 从启动参数`spring.profiles.default`获取
String profiles = getProperty(DEFAULT_PROFILES_PROPERTY_NAME);
if (StringUtils.hasText(profiles)) {
// 设置为默认的`profile`
setDefaultProfiles(StringUtils.commaDelimitedListToStringArray(
StringUtils.trimAllWhitespace(profiles)));
}
}
return this.defaultProfiles;
}
}


@Override
public void setDefaultProfiles(String... profiles) {
Assert.notNull(profiles, "Profile array must not be null");
synchronized (this.defaultProfiles) {
// 清空
this.defaultProfiles.clear();
for (String profile : profiles) {
// 验证
validateProfile(profile);
// 添加为默认`profile`
this.defaultProfiles.add(profile);
}
}
}

@Override
public boolean acceptsProfiles(String... profiles) {
Assert.notEmpty(profiles, "Must specify at least one profile");
// 只要有一个满足条件,即返回`true`
for (String profile : profiles) {
if (StringUtils.hasLength(profile) && profile.charAt(0) == '!') {
// 使用取反标记时,只要不等,就认为是可以使用
if (!isProfileActive(profile.substring(1))) {
return true;
}
}
else if (isProfileActive(profile)) {
return true;
}
}
return false;
}

// 判断`profile`是否可用,如果没有可用的`profile`,从默认的`profile`匹配,如果匹配到也认为是可以使用
protected boolean isProfileActive(String profile) {
validateProfile(profile);
Set<String> currentActiveProfiles = doGetActiveProfiles();
return (currentActiveProfiles.contains(profile) ||
(currentActiveProfiles.isEmpty() && doGetDefaultProfiles().contains(profile)));
}

// 验证`profile`是否可用,主要是字符串验证(长度和非法字符'!')
protected void validateProfile(String profile) {
if (!StringUtils.hasText(profile)) {
throw new IllegalArgumentException("Invalid profile [" + profile + "]: must contain text");
}
if (profile.charAt(0) == '!') {
throw new IllegalArgumentException("Invalid profile [" + profile + "]: must not begin with ! operator");
}
}

@Override
public MutablePropertySources getPropertySources() {
return this.propertySources;
}

@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public Map<String, Object> getSystemEnvironment() {
// 判断是否忽略获取系统属性
if (suppressGetenvAccess()) {
return Collections.emptyMap();
}
try {
return (Map) System.getenv();
}
catch (AccessControlException ex) {
// `ReadOnlySystemAttributesMap`为`Map`的一个实现
// 如果初始化时未获取到系统配置,则在需要读取属性值时重新获取
return (Map) new ReadOnlySystemAttributesMap() {
@Override
protected String getSystemAttribute(String attributeName) {
try {
return System.getenv(attributeName);
}
catch (AccessControlException ex) {
if (logger.isInfoEnabled()) {
logger.info(String.format("Caught AccessControlException when accessing system " +
"environment variable [%s]; its value will be returned [null]. Reason: %s",
attributeName, ex.getMessage()));
}
return null;
}
}
};
}
}

// 判断是否忽略获取系统属性
// 从`spring.properties`文件中读取(该文件可以新建在`resources`文件夹下)
protected boolean suppressGetenvAccess() {
return SpringProperties.getFlag(IGNORE_GETENV_PROPERTY_NAME);
}

@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public Map<String, Object> getSystemProperties() {
try {
return (Map) System.getProperties();
}
catch (AccessControlException ex) {
// `ReadOnlySystemAttributesMap`为`Map`的一个实现
// 如果初始化时未获取到系统配置,则在需要读取属性值时重新获取
return (Map) new ReadOnlySystemAttributesMap() {
@Override
protected String getSystemAttribute(String attributeName) {
try {
return System.getProperty(attributeName);
}
catch (AccessControlException ex) {
if (logger.isInfoEnabled()) {
logger.info(String.format("Caught AccessControlException when accessing system " +
"property [%s]; its value will be returned [null]. Reason: %s",
attributeName, ex.getMessage()));
}
return null;
}
}
};
}
}

@Override
public void merge(ConfigurableEnvironment parent) {
// 合并`PropertySource`,默认追加在最后
// `PropertySources`存在优先级(顺序),使用该方法时需要注意
for (PropertySource<?> ps : parent.getPropertySources()) {
if (!this.propertySources.contains(ps.getName())) {
this.propertySources.addLast(ps);
}
}
// 合并可用`profile`
String[] parentActiveProfiles = parent.getActiveProfiles();
if (!ObjectUtils.isEmpty(parentActiveProfiles)) {
synchronized (this.activeProfiles) {
for (String profile : parentActiveProfiles) {
this.activeProfiles.add(profile);
}
}
}
// 合并默认`profile`
String[] parentDefaultProfiles = parent.getDefaultProfiles();
if (!ObjectUtils.isEmpty(parentDefaultProfiles)) {
synchronized (this.defaultProfiles) {
// 移除`default`
this.defaultProfiles.remove(RESERVED_DEFAULT_PROFILE_NAME);
for (String profile : parentDefaultProfiles) {
this.defaultProfiles.add(profile);
}
}
}
}


// 省略部分实现...

}

StandardEnvironment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class StandardEnvironment extends AbstractEnvironment {

public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";

public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";

// 此处添加了两个`PropertySource`
// 如果看`StandardServletEnvironment`实现,还有添加`servlet`相关属性配置
@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}

}