先看一下最简单的spring boot中环境中有些什么东西,首先spring boot的版本是1.5.9
@RequestMapping(value = "/hello")
@RestController
public class HelloWorld {
@Autowired
private AbstractEnvironment environment;
@RequestMapping(value = "/world", method = RequestMethod.GET)
public String world() {
System.out.println(environment);
System.out.println(environment.getSystemEnvironment());
System.out.println(environment.getSystemProperties());
for (String s : environment.getActiveProfiles()){
System.out.println(s);
}
System.out.println("qwe");
for (String s : environment.getDefaultProfiles()){
System.out.println(s);
}
return "qwe";
}
}
测试代码
StandardServletEnvironment {activeProfiles=[], defaultProfiles=[default], propertySources=[MapPropertySource {name='server.ports'}, StubPropertySource {name='servletConfigInitParams'}, ServletContextPropertySource {name='servletContextInitParams'}, MapPropertySource {name='systemProperties'}, SystemEnvironmentPropertySource {name='systemEnvironment'}, RandomValuePropertySource {name='random'}, PropertiesPropertySource {name='applicationConfig: [classpath:/application.properties]'}]}
这是环境里面所有的变量,接下来就看看这些环境变量是从哪里生成的。首先可以从run的方法中进入,可以看到prepareEnvironment方法用来生成环境。
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
listeners.environmentPrepared((ConfigurableEnvironment)environment);
if (!this.webEnvironment) {
environment = (new EnvironmentConverter(this.getClassLoader())).convertToStandardEnvironmentIfNecessary((ConfigurableEnvironment)environment);
}
return (ConfigurableEnvironment)environment;
}
只需要看3个方法就可以getOrCreateEnvironment,configureEnvironment,environmentPrepared,先来看看getOrCreateEnvironment
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
} else {
return (ConfigurableEnvironment)(this.webEnvironment ? new StandardServletEnvironment() : new StandardEnvironment());
}
}
这里只做了一步,new StandardServletEnvironment()。接下来看看会初始化一些什么东西
StandardServletEnvironment->StandardEnvironment->AbstractEnvironment。这是一个继承关系,先去初始化AbstractEnvironment中的构造函数
public AbstractEnvironment() {
this.propertySources = new MutablePropertySources(this.logger);
this.propertyResolver = new PropertySourcesPropertyResolver(this.propertySources);
this.customizePropertySources(this.propertySources);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Initialized " + this.getClass().getSimpleName() + " with PropertySources " + this.propertySources);
}
}
customizePropertySources方法进行初始化,接下来在StandardServletEnvironment找到了方法
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new StubPropertySource("servletConfigInitParams"));
propertySources.addLast(new StubPropertySource("servletContextInitParams"));
if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
propertySources.addLast(new JndiPropertySource("jndiProperties"));
}
super.customizePropertySources(propertySources);
}
这里初始化了servlet的一些参数。这里还调用了父类的方法,接下来看看父类中的方法
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new MapPropertySource("systemProperties", this.getSystemProperties()));
propertySources.addLast(new SystemEnvironmentPropertySource("systemEnvironment", this.getSystemEnvironment()));
}
发现这里初始化了系统环境变量。
至此大部分的初始化已经完成。
接下来看看configureEnvironment
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
this.configurePropertySources(environment, args);
this.configureProfiles(environment, args);
}
进入第一个方法
protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
MutablePropertySources sources = environment.getPropertySources();
if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties));
}
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(name + "-" + args.hashCode(), args));
composite.addPropertySource(source);
sources.replace(name, composite);
} else {
sources.addFirst(new SimpleCommandLinePropertySource(args));
}
}
}
这里是进行命令行参数的初始化
最后看一下environmentPrepared,本质是ConfigFileApplicationListener类
当广播来的时候,会调用onApplicationEnvironmentPreparedEvent
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
List postProcessors = this.loadPostProcessors();
postProcessors.add(this);
AnnotationAwareOrderComparator.sort(postProcessors);
Iterator var3 = postProcessors.iterator();
while(var3.hasNext()) {
EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var3.next();
postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
}
}
进入postProcessEnvironment方法
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
this.addPropertySources(environment, application.getResourceLoader());
this.configureIgnoreBeanInfo(environment);
this.bindToSpringApplication(environment, application);
}
进入addPropertySources方法
protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
RandomValuePropertySource.addToEnvironment(environment);
(new ConfigFileApplicationListener.Loader(environment, resourceLoader)).load();
}
在这里RandomValuePropertySource添加了环境变量
接下来就差最后一个.yml和.properties文件的加载了。
进入load()方法
public void load() {
this.propertiesLoader = new PropertySourcesLoader();
this.activatedProfiles = false;
this.profiles = Collections.asLifoQueue(new LinkedList());
this.processedProfiles = new LinkedList();
Set initialActiveProfiles = this.initializeActiveProfiles();
this.profiles.addAll(this.getUnprocessedActiveProfiles(initialActiveProfiles));
if (this.profiles.isEmpty()) {
String[] var2 = this.environment.getDefaultProfiles();
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
String defaultProfileName = var2[var4];
ConfigFileApplicationListener.Profile defaultProfile = new ConfigFileApplicationListener.Profile(defaultProfileName, true);
if (!this.profiles.contains(defaultProfile)) {
this.profiles.add(defaultProfile);
}
}
}
this.profiles.add((Object)null);
ConfigFileApplicationListener.Profile profile;
label41:
for(; !this.profiles.isEmpty(); this.processedProfiles.add(profile)) {
profile = (ConfigFileApplicationListener.Profile)this.profiles.poll();
Iterator var8 = this.getSearchLocations().iterator();
while(true) {
while(true) {
if (!var8.hasNext()) {
continue label41;
}
String location = (String)var8.next();
if (!location.endsWith("/")) {
this.load(location, (String)null, profile);
} else {
Iterator var10 = this.getSearchNames().iterator();
while(var10.hasNext()) {
String name = (String)var10.next();
this.load(location, name, profile);
}
}
}
}
}
this.addConfigurationProperties(this.propertiesLoader.getPropertySources());
}
先看最下面的循环其中location是需要文件的位置,根据顺序排下来是这样的。file:./config/ 、 file:./ 、 classpath:/config/ 、classpath:/ 。name是application,profile可能是"default",这两个分别对应着application-default.yml。
再看看内部的load方法
private void load(String location, String name, ConfigFileApplicationListener.Profile profile) {
String group = "profile=" + (profile == null ? "" : profile);
String ext;
if (!StringUtils.hasText(name)) {
this.loadIntoGroup(group, location, profile);
} else {
for(Iterator var5 = this.propertiesLoader.getAllFileExtensions().iterator(); var5.hasNext(); this.loadIntoGroup(group, location + name + "." + ext, profile)) {
ext = (String)var5.next();
if (profile != null) {
this.loadIntoGroup(group, location + name + "-" + profile + "." + ext, (ConfigFileApplicationListener.Profile)null);
Iterator var7 = this.processedProfiles.iterator();
while(var7.hasNext()) {
ConfigFileApplicationListener.Profile processedProfile = (ConfigFileApplicationListener.Profile)var7.next();
if (processedProfile != null) {
this.loadIntoGroup(group, location + name + "-" + processedProfile + "." + ext, profile);
}
}
this.loadIntoGroup(group, location + name + "-" + profile + "." + ext, profile);
}
}
}
}
可以看到在for循环的内部有一个this.loadIntoGroup(group, location + name + "." + ext, profile)
application.properties就是在这里进行初始化