org.springframework.core.env.Environment 类图
0.prepareEnvironment
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// 1. Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
//2.
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
//3. environmentPrepared: 加载spring.config...
listeners.environmentPrepared(bootstrapContext, environment);
//确保defaultProperties优先级最低
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),"Environment prefix cannot be set via properties.");
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
//略...
ConfigurationPropertySources.attach(environment);
return environment;
}
1. getOrCreateEnvironment() : ApplicationServletEnvironment
see: AnnotationConfigServletWebServerApplicationContext.Factory.createEnvironment()
public interface Environment extends PropertyResolver {
String[] getActiveProfiles();
}
public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {
}
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";
private final MutablePropertySources propertySources;
public AbstractEnvironment() {
this(new MutablePropertySources());
}
}
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";
protected StandardEnvironment(MutablePropertySources propertySources) {
super(propertySources);
}
@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast( new PropertiesPropertySource("systemProperties", getSystemProperties())); //优先级4
propertySources.addLast(new SystemEnvironmentPropertySource("systemEnvironment", getSystemEnvironment()));//优先级5
}
}
public class StandardServletEnvironment extends StandardEnvironment implements ConfigurableWebEnvironment {
private static final boolean jndiPresent = ClassUtils.isPresent("javax.naming.InitialContext", StandardServletEnvironment.class.getClassLoader());
public StandardServletEnvironment() {
}
protected StandardServletEnvironment(MutablePropertySources propertySources) {
super(propertySources);
}
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new PropertySource.StubPropertySource("servletConfigInitParams")); //优先级1
propertySources.addLast(new PropertySource.StubPropertySource("servletContextInitParams"));//优先级2
if (jndiPresent && JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
propertySources.addLast(new JndiPropertySource("jndiProperties"));//优先级3
}
super.customizePropertySources(propertySources);//parent
}
public void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
WebApplicationContextUtils.initServletPropertySources(this.getPropertySources(), servletContext, servletConfig);
}
}
class ApplicationServletEnvironment extends StandardServletEnvironment {
}
MutablePropertySources
public class MutablePropertySources implements PropertySources { private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<>(); }
1.1 配置文件优先级
此阶段之后,MutablePropertySources存在如下PropertySource:
servletConfigInitParams
servletContextInitParams
jndiProperties
systemProperties
systemEnvironment
2. configureEnvironment(environment, applicationArguments.getSourceArgs());
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
if (this.addConversionService) {
//ConversionService
environment.setConversionService(new ApplicationConversionService());
}
//2.1
configurePropertySources(environment, args);
//2.2 空实现
configureProfiles(environment, args);
}
//2.1
protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
MutablePropertySources sources = environment.getPropertySources();
if (!CollectionUtils.isEmpty(this.defaultProperties)) {
//最终会调用: sources.addLast(propertySource); // defaultProperties 优先级最低
DefaultPropertiesPropertySource.addOrMerge(this.defaultProperties, sources);
}
if (this.addCommandLineProperties && args.length > 0) {
String name = "commandLineArgs";
if (sources.contains(name)) {
PropertySource<?> source = sources.get(name);
CompositePropertySource composite = new CompositePropertySource(name);
composite
.addPropertySource(new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
composite.addPropertySource(source);
sources.replace(name, composite);
}
else {
//commandline args 优先级最高 :
sources.addFirst(new SimpleCommandLinePropertySource(args));
}
}
}
2.1 配置文件优先级
- CommandLinePropertySource
servletConfigInitParams
servletContextInitParams
jndiProperties
systemProperties
systemEnvironment
- defaultPropertiesSource
3. listeners.environmentPrepared(bootstrapContext, environment);
3.1 EnvironmentPostProcessorApplicationListener.environmentPrepared()
//1.
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
ConfigurableEnvironment environment) {
/**
* ====spring.factories===
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.env.EnvironmentPostProcessorApplicationListener - 2
*/
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));
}
}
//2
public class EnvironmentPostProcessorApplicationListener implements SmartApplicationListener, Ordered {
private final Function<ClassLoader, EnvironmentPostProcessorsFactory> postProcessorsFactory;
//2.1
public EnvironmentPostProcessorApplicationListener() {
/**
* 加载spring.factories load EnvironmentPostProcessor
* return new ReflectionEnvironmentPostProcessorsFactory(classLoader,SpringFactoriesLoader.loadFactoryNames(EnvironmentPostProcessor.class, classLoader));
*/
this(EnvironmentPostProcessorsFactory::fromSpringFactories, new DeferredLogs());
}
//2.2
public EnvironmentPostProcessorApplicationListener(EnvironmentPostProcessorsFactory postProcessorsFactory) {
this((classloader) -> postProcessorsFactory, new DeferredLogs());
}
//2.3
EnvironmentPostProcessorApplicationListener(
Function<ClassLoader, EnvironmentPostProcessorsFactory> postProcessorsFactory, DeferredLogs deferredLogs) {
this.postProcessorsFactory = postProcessorsFactory;
this.deferredLogs = deferredLogs;
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
//2.4
if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
}
//略....
}
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
SpringApplication application = event.getSpringApplication();
//2.5. 通过postProcessorsFactory 获取EnvironmentPostProcessor --> 加载spring.factories load EnvironmentPostProcessor
for (EnvironmentPostProcessor postProcessor : getEnvironmentPostProcessors(application.getResourceLoader(),event.getBootstrapContext())) {
//2.6. for-each 执行 postProcessEnvironment
postProcessor.postProcessEnvironment(environment, application);
}
}
}
3.2 spring.factories: EnvironmentPostProcessor
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor,\
org.springframework.boot.env.RandomValuePropertySourceEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\
org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor
优先级
public class CloudFoundryVcapEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
private static final String VCAP_APPLICATION = "VCAP_APPLICATION";
private static final String VCAP_SERVICES = "VCAP_SERVICES";
private int order = ConfigDataEnvironmentPostProcessor.ORDER - 1;
}
public class RandomValuePropertySourceEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
public static final int ORDER = Ordered.HIGHEST_PRECEDENCE + 1;
}
public class SystemEnvironmentPropertySourceEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
public static final int DEFAULT_ORDER = SpringApplicationJsonEnvironmentPostProcessor.DEFAULT_ORDER - 1; // ==== Ordered.HIGHEST_PRECEDENCE + 4
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
String sourceName = "systemEnvironment";
PropertySource<?> propertySource = environment.getPropertySources().get(sourceName);
if (propertySource != null) {
replacePropertySource(environment, sourceName, propertySource, application.getEnvironmentPrefix());
}
}
}
public class SpringApplicationJsonEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
public static final String SPRING_APPLICATION_JSON_PROPERTY = "spring.application.json";
public static final String SPRING_APPLICATION_JSON_ENVIRONMENT_VARIABLE = "SPRING_APPLICATION_JSON";
private static final String SERVLET_ENVIRONMENT_CLASS = "org.springframework.web." + "context.support.StandardServletEnvironment";
private static final Set<String> SERVLET_ENVIRONMENT_PROPERTY_SOURCES = new LinkedHashSet<>(
Arrays.asList(StandardServletEnvironment.JNDI_PROPERTY_SOURCE_NAME,
StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME,
StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 5;
}
public class ConfigDataEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
public static final int ORDER = Ordered.HIGHEST_PRECEDENCE + 10;
}
public class DebugAgentEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
private static final String REACTOR_DEBUGAGENT_CLASS = "reactor.tools.agent.ReactorDebugAgent";
private static final String DEBUGAGENT_ENABLED_CONFIG_KEY = "spring.reactor.debug-agent.enabled";
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
3.3 ConfigDataEnvironmentPostProcessor.postProcessEnvironment()
public class ConfigDataEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
//获取additionalProfiles
postProcessEnvironment(environment, application.getResourceLoader(), application.getAdditionalProfiles());
}
void postProcessEnvironment(ConfigurableEnvironment environment, ResourceLoader resourceLoader,
Collection<String> additionalProfiles) {
resourceLoader = (resourceLoader != null) ? resourceLoader : new DefaultResourceLoader();
//1.getConfigDataEnvironment()
//2.ConfigDataEnvironment.processAndApply();
getConfigDataEnvironment(environment, resourceLoader, additionalProfiles).processAndApply();
}
ConfigDataEnvironment getConfigDataEnvironment(ConfigurableEnvironment environment, ResourceLoader resourceLoader,
Collection<String> additionalProfiles) {
//1
return new ConfigDataEnvironment(this.logFactory, this.bootstrapContext, environment, resourceLoader,additionalProfiles, this.environmentUpdateListener);
}
}
3.3.1 new ConfigDataEnvironment()
class ConfigDataEnvironment {
static final String LOCATION_PROPERTY = "spring.config.location";
static final String ADDITIONAL_LOCATION_PROPERTY = "spring.config.additional-location";
static final String IMPORT_PROPERTY = "spring.config.import";
static final String ON_NOT_FOUND_PROPERTY = "spring.config.on-not-found";
static final ConfigDataLocation[] DEFAULT_SEARCH_LOCATIONS;
static {
List<ConfigDataLocation> locations = new ArrayList<>();
locations.add(ConfigDataLocation.of("optional:classpath:/;optional:classpath:/config/"));
locations.add(ConfigDataLocation.of("optional:file:./;optional:file:./config/;optional:file:./config/*/"));
DEFAULT_SEARCH_LOCATIONS = locations.toArray(new ConfigDataLocation[0]);
}
//1
ConfigDataEnvironment(DeferredLogFactory logFactory, ConfigurableBootstrapContext bootstrapContext,
ConfigurableEnvironment environment, ResourceLoader resourceLoader, Collection<String> additionalProfiles,
ConfigDataEnvironmentUpdateListener environmentUpdateListener) {
Binder binder = Binder.get(environment);
UseLegacyConfigProcessingException.throwIfRequested(binder);
this.logFactory = logFactory;
this.logger = logFactory.getLog(getClass());
this.notFoundAction = binder.bind(ON_NOT_FOUND_PROPERTY, ConfigDataNotFoundAction.class)
.orElse(ConfigDataNotFoundAction.FAIL);
this.bootstrapContext = bootstrapContext;
this.environment = environment;
this.resolvers = createConfigDataLocationResolvers(logFactory, bootstrapContext, binder, resourceLoader);
this.additionalProfiles = additionalProfiles;
this.environmentUpdateListener = (environmentUpdateListener != null) ? environmentUpdateListener
: ConfigDataEnvironmentUpdateListener.NONE;
this.loaders = new ConfigDataLoaders(logFactory, bootstrapContext, resourceLoader.getClassLoader());
this.contributors = createContributors(binder); // 从spring的各个目录加载配置文件, build contributors 略....
}
}
3.3.2 ConfigDataEnvironment.processAndApply();
class ConfigDataEnvironment {
//2
void processAndApply() {
ConfigDataImporter importer = new ConfigDataImporter(this.logFactory, this.notFoundAction, this.resolvers,
this.loaders);
registerBootstrapBinder(this.contributors, null, DENY_INACTIVE_BINDING);
ConfigDataEnvironmentContributors contributors = processInitial(this.contributors, importer);
ConfigDataActivationContext activationContext = createActivationContext(
contributors.getBinder(null, BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE));
contributors = processWithoutProfiles(contributors, importer, activationContext); //2.1 without profile
activationContext = withProfiles(contributors, activationContext);
contributors = processWithProfiles(contributors, importer, activationContext); //2.2 with profile
//2.3 applyToEnvironment
applyToEnvironment(contributors, activationContext, importer.getLoadedLocations(),importer.getOptionalLocations());
}
//2.3
private void applyToEnvironment(ConfigDataEnvironmentContributors contributors,
ConfigDataActivationContext activationContext, Set<ConfigDataLocation> loadedLocations,
Set<ConfigDataLocation> optionalLocations) {
checkForInvalidProperties(contributors);
checkMandatoryLocations(contributors, activationContext, loadedLocations, optionalLocations);
MutablePropertySources propertySources = this.environment.getPropertySources();
//2.3.1
applyContributor(contributors, activationContext, propertySources);
DefaultPropertiesPropertySource.moveToEnd(propertySources); //依旧确保default properties 优先级最低
Profiles profiles = activationContext.getProfiles();
this.environment.setDefaultProfiles(StringUtils.toStringArray(profiles.getDefault()));
this.environment.setActiveProfiles(StringUtils.toStringArray(profiles.getActive()));
this.environmentUpdateListener.onSetProfiles(profiles);
}
//2.3.1
private void applyContributor(ConfigDataEnvironmentContributors contributors,
ConfigDataActivationContext activationContext, MutablePropertySources propertySources) {
for (ConfigDataEnvironmentContributor contributor : contributors) {
PropertySource<?> propertySource = contributor.getPropertySource();
if (contributor.getKind() == ConfigDataEnvironmentContributor.Kind.BOUND_IMPORT && propertySource != null) {
if (!contributor.isActive(activationContext)) {
//若active 不匹配,则跳过
this.logger.trace(LogMessage.format("Skipping inactive property source '%s'", propertySource.getName()));
}
else {
propertySources.addLast(propertySource); //优先级最低....
this.environmentUpdateListener.onPropertySourceAdded(propertySource, contributor.getLocation(),contributor.getResource());
}
}
}
}
}
3.4 配置文件优先级
- CommandLinePropertySource
servletConfigInitParams
servletContextInitParams
jndiProperties
systemProperties
systemEnvironment
- spring.config
- CloudFoundryVcapEnvironmentPostProcessor
- RandomValuePropertySourceEnvironmentPostProcessor
- SystemEnvironmentPropertySourceEnvironmentPostProcessor
- SpringApplicationJsonEnvironmentPostProcessor
- ConfigDataEnvironmentPostProcessor
- DebugAgentEnvironmentPostProcessor
- defaultPropertiesSource