Fork me on GitHub

SpringBoot (2) Environment

SpringBoot (2) Environment

SpringBoot版本

SpringBoot 2.1.6

prepareEnvironment

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
      ApplicationArguments applicationArguments) {
   // Create and configure the environment
   ConfigurableEnvironment environment = getOrCreateEnvironment();
   configureEnvironment(environment, applicationArguments.getSourceArgs());
   listeners.environmentPrepared(environment);
   bindToSpringApplication(environment);
   if (!this.isCustomEnvironment) {
      environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
            deduceEnvironmentClass());
   }
   ConfigurationPropertySources.attach(environment);
   return environment;
}

getOrCreateEnvironment

在run方法中prepareEnvironment准备创建environment,根据type来决定使用哪种env,如果需要使用web一般来说默认都是StandardServletEnvironment

private ConfigurableEnvironment getOrCreateEnvironment() {
   if (this.environment != null) {
      return this.environment;
   }
   switch (this.webApplicationType) {
   case SERVLET:
      return new StandardServletEnvironment();
   case REACTIVE:
      return new StandardReactiveWebEnvironment();
   default:
      return new StandardEnvironment();
   }
}

configureEnvironment

当创建了一个environment,首先需要做的就是对这个env做配置

/**
	 * Template method delegating to
	 * {@link #configurePropertySources(ConfigurableEnvironment, String[])} and
	 * {@link #configureProfiles(ConfigurableEnvironment, String[])} in that order.
	 * Override this method for complete control over Environment customization, or one of
	 * the above for fine-grained control over property sources or profiles, respectively.
	 * @param environment this application's environment
	 * @param args arguments passed to the {@code run} method
	 * @see #configureProfiles(ConfigurableEnvironment, String[])
	 * @see #configurePropertySources(ConfigurableEnvironment, String[])
	 */
	protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
		if (this.addConversionService) {
			ConversionService conversionService = ApplicationConversionService.getSharedInstance();
			environment.setConversionService((ConfigurableConversionService) conversionService);
		}
		configurePropertySources(environment, args);
		configureProfiles(environment, args);
	}

listeners.environmentPrepared

当environment准备完成,就要发布监听事件

listeners.environmentPrepared(environment);

postProcessEnvironment

ConfigFileApplicationListener接收到env的事件,然后做相应的处理。

@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
		addPropertySources(environment, application.getResourceLoader());
}

addPropertySources

准备加载配置文件property source到指定的environment

/**
 * Add config file property sources to the specified environment.
 * @param environment the environment to add source to
 * @param resourceLoader the resource loader
 * @see #addPostProcessors(ConfigurableApplicationContext)
 */
protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
   RandomValuePropertySource.addToEnvironment(environment);
   new Loader(environment, resourceLoader).load();
}

用environment和resourceloader,实例化Loader,来load资源。

赋值environment,placeholdersResolver,resourceLoader,propertySourceLoaders

Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
   this.environment = environment;
   this.placeholdersResolver = new PropertySourcesPlaceholdersResolver(this.environment);
   this.resourceLoader = (resourceLoader != null) ? resourceLoader : new DefaultResourceLoader();
   this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class,
         getClass().getClassLoader());
}

load

load可以说是hin复杂的一部分,嵌套的太深,但是干的活基本还是load,加载。

public void load() {
   this.profiles = new LinkedList<>();
   this.processedProfiles = new LinkedList<>();
   this.activatedProfiles = false;
   this.loaded = new LinkedHashMap<>();
   initializeProfiles();
   while (!this.profiles.isEmpty()) {
      Profile profile = this.profiles.poll();
      if (profile != null && !profile.isDefaultProfile()) {
         addProfileToEnvironment(profile.getName());
      }
      load(profile, this::getPositiveProfileFilter, addToLoaded(MutablePropertySources::addLast, false));
      this.processedProfiles.add(profile);
   }
   resetEnvironmentProfiles(this.processedProfiles);
   load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true));
   addLoadedPropertySources();
}
调用了带3参的load
private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
   getSearchLocations().forEach((location) -> {
      boolean isFolder = location.endsWith("/");
      Set<String> names = isFolder ? getSearchNames() : NO_SEARCH_NAMES;
      names.forEach((name) -> load(location, name, profile, filterFactory, consumer));
   });
}
调用了带5参的load

这个load里面会对load做递归call。

private void load(String location, String name, Profile profile, DocumentFilterFactory filterFactory,
      DocumentConsumer consumer) {
   if (!StringUtils.hasText(name)) {
      for (PropertySourceLoader loader : this.propertySourceLoaders) {
         if (canLoadFileExtension(loader, location)) {
            load(loader, location, profile, filterFactory.getDocumentFilter(profile), consumer);
            return;
         }
      }
   }
   Set<String> processed = new HashSet<>();
   for (PropertySourceLoader loader : this.propertySourceLoaders) {
      for (String fileExtension : loader.getFileExtensions()) {
         if (processed.add(fileExtension)) {
            loadForFileExtension(loader, location + name, "." + fileExtension, profile, filterFactory,
                  consumer);
         }
      }
   }
}

load的核心基本完成一多半了。

然后开始resetEnvironmentProfiles,为了对env的profile做一次整理

addLoadedPropertySources

最后就是addLoadedPropertySources,把已经封装成为propertySource的资源放到this.environment.getPropertySources()

private void addLoadedPropertySources() {
   MutablePropertySources destination = this.environment.getPropertySources();
   List<MutablePropertySources> loaded = new ArrayList<>(this.loaded.values());
   Collections.reverse(loaded);
   String lastAdded = null;
   Set<String> added = new HashSet<>();
   for (MutablePropertySources sources : loaded) {
      for (PropertySource<?> source : sources) {
         if (added.add(source.getName())) {
            addLoadedPropertySource(destination, lastAdded, source);
            lastAdded = source.getName();
         }
      }
   }
}

private void addLoadedPropertySource(MutablePropertySources destination, String lastAdded,
      PropertySource<?> source) {
   if (lastAdded == null) {
      if (destination.contains(DEFAULT_PROPERTIES)) {
         destination.addBefore(DEFAULT_PROPERTIES, source);
      }
      else {
         destination.addLast(source);
      }
   }
   else {
      destination.addAfter(lastAdded, source);
   }
}

小结

environment作为springboot启动的环境准备工作,不可或缺,几乎所有的加载都在这里完成了,

OK,又水了一篇

key word

environment

ConfigFileApplicationListener

EnvironmentPostProcessor

Loader

主目录

SpringBoot框架及源码分析

posted @ 2021-02-16 15:58  WilliamCui  阅读(242)  评论(0编辑  收藏  举报