zoukankan      html  css  js  c++  java
  • 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框架及源码分析

  • 相关阅读:
    Android学习笔记----天地图API开发之UnsatisfiedLinkError
    Android学习笔记----ArcGIS在线地图服务(Android API)坐标纠偏
    Android学习笔记----Java字符串MD5加密
    Android学习笔记----Java中的字符串比较
    MySQL数据库导入错误:ERROR 1064 (42000) 和 ERROR at line xx: Unknown command ''.
    新浪微博POI点签到数据及可视化的初步成果
    Chrome调试本地文件无法使用window.opener对象进行窗口间值传递
    132、Android安全机制(2) Android Permission权限控制机制(转载)
    用addOnGlobalLayoutListener获取View的宽高
    Android Studio解决unspecified on project app resolves to an APK archive which is not supported
  • 原文地址:https://www.cnblogs.com/dreamtaker/p/14406495.html
Copyright © 2011-2022 走看看