首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >「Spring 源码分析」Profile

「Spring 源码分析」Profile

原创
作者头像
花言不知梦
修改2020-05-18 11:17:15
9830
修改2020-05-18 11:17:15
举报
文章被收录于专栏:花言不知梦花言不知梦

Profile

profile 定义了一组有逻辑关系的 bean定义,当且仅当 profile 被激活的时候,才会注入到容器当中。也就是说,程序只需要构建一次,就可以部署到多个环境当中,而不用修改所有配置,指定哪一个profile需要被激活即可

源码分析(细节比较多,得捋清楚)

主要是通过ConfigFileApplicationListener的内部类Loader进行加载

  1. 更新 profiles集,添加存在已经激活的profile值,如果不存在,添加默认指定的profile值到profiles集当中
  2. 确定搜索范围(路径),获取配置文件名({name}-{profile}),使用PropertiesPropertySourceLoader和YamlPropertySourceLoader这两个加载器添加相应的文件扩展名,进行加载
  3. 将加载后的loaded列表逆序,遍历该列表中的每一个MutablePropertySources对象,依次注入到environment对象的propertySources属性值当中,这里就意味着完成profile所指定的一组bean的注册工作
1. 进入 onApplicationEnvironmentPreparedEvent(event)方法 -- ConfigFileApplicationListener类
   该方法的作用是遍历所有的后处理器,依次调用后处理器,执行相应的方法
   我们需要关注的是 ConfigFileApplicationListener类 这个后处理器执行的操作
   private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
        // 遍历所有的后处理器,只要是 EnvironmentPostProcessor类型,就添加到 postProcessors列表当中
        List<EnvironmentPostProcessor> postProcessors = this.loadPostProcessors();
        // 把本身也添加到 postProcessors列表当中
        // 因为 ConfigFileApplicationListener类 实现了 EnvironmentPostProcessor接口
        postProcessors.add(this);
        // 对 postProcessors列表中的后处理器按Order值进行排序
        AnnotationAwareOrderComparator.sort(postProcessors);
        Iterator var3 = postProcessors.iterator();

        while(var3.hasNext()) {
            // 获取后处理器
            EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var3.next();
            // 执行后处理器的 postProcessEnvironment方法
            postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
        }

   }
    
2. 进入 postProcessEnvironment(event.getEnvironment(), event.getSpringApplication()) -- ConfigFileApplicationListener类
   该方法的作用是调用自定义的 addPropertySources方法向环境中添加属性源
   public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        // 向环境中添加属性源
        this.addPropertySources(environment, application.getResourceLoader());
   }
   
3. 进入 addPropertySources(environment, application.getResourceLoader())方法
   该方法的作用是向环境中添加属性源,主要是RandomValuePropertySource 和 application-{profile}.(properties|yml)配置文件中的属性源
   protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
        // 添加 RandomValuePropertySource(随机类型)属性源
        RandomValuePropertySource.addToEnvironment(environment);
        // 从 application-{profile}.(properties|yml)配置文件中加载属性源
        (new ConfigFileApplicationListener.Loader(environment, resourceLoader)).load();
   }
   
   == ConfigFileApplicationListener的内部类Loader 构造方法==
   Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
        this.logger = ConfigFileApplicationListener.this.logger;
        this.loadDocumentsCache = new HashMap();
        this.environment = environment;
        // 初始化占位符解析器
        this.placeholdersResolver = new PropertySourcesPlaceholdersResolver(this.environment);
        // 一般情况下,使用默认的类加载器
        this.resourceLoader = (ResourceLoader)(resourceLoader != null ? resourceLoader : new DefaultResourceLoader());
        // 使用 SpringFactoriesLoader类加载所有jar包下的 META-INF目录的 spring.factories文件的 PropertySourceLoader类数组
        // 最终会得到两个实现类,一个是PropertiesPropertySourceLoader类,一个是YamlPropertySourceLoader类
        // PropertiesPropertySourceLoader类 支持properties和xml文件,解析成Properties,然后封装成PropertiesPropertySource
        // YamlPropertySourceLoader类 支持yml和yaml文件,解析成Map,然后封装成MapPropertySource
        this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class, this.getClass().getClassLoader());
    }
   
4. 进入 load()方法
   该方法的作用是加载所有可能的profile
   void load() {
        FilteredPropertySource.apply(this.environment, "defaultProperties", ConfigFileApplicationListener.LOAD_FILTERED_PROPERTY, (defaultProperties) -> {
            // 初始化集合
            // 未处理的数据集合
            this.profiles = new LinkedList();
            // 已处理的数据集合
            this.processedProfiles = new LinkedList();
            // 被 spring.profiles.active指定的集合
            this.activatedProfiles = false;
            this.loaded = new LinkedHashMap();
            // 4.1 加载存在已经激活的 profiles
            this.initializeProfiles();
            
            // 遍历profiles
            while(!this.profiles.isEmpty()) {
                // 从 profiles集合中获取 profile
                ConfigFileApplicationListener.Profile profile = (ConfigFileApplicationListener.Profile)this.profiles.poll();
                // 如果 profile不是默认指定的 profile,且不为null
                // 其中,isDefaultProfile方法体定义 profile != null && !profile.isDefaultProfile()
                if (this.isDefaultProfile(profile)) {
                    // 添加 profiles资源到环境中
                    this.addProfileToEnvironment(profile.getName());
                }
                
                // 4.2 确定搜索范围,获取对应的配置文件名,并使用相应加载器加载
                this.load(profile, this::getPositiveProfileFilter, this.addToLoaded(MutablePropertySources::addLast, false));
                // 将处理完的 profile添加到 processedProfiles列表当中,表示已经处理完成
                this.processedProfiles.add(profile);
            }
            
            // 采用消极策略的DocumentFilterFactory对象进行处理
            this.load((ConfigFileApplicationListener.Profile)null, this::getNegativeProfileFilter, this.addToLoaded(MutablePropertySources::addFirst, true));
            // 顺序颠倒下,保证了优先add的是带profile的,而默认的profile是优先级最低
            this.addLoadedPropertySources();
            // 更新 activeProfiles列表
            this.applyActiveProfiles(defaultProperties);
        });
    }

4.1 进入 initializeProfiles( )方法,更新 profiles集

  1. 加载 通过spring.profiles.active指定激活的profile 和 通过spring.profiles.include指定叠加激活的profile
  2. 如果 profiles集为空,则尝试加载 通过spring.profiles.default指定默认的profile,如果没有,就返回"default"
 4.1 进入 this.initializeProfiles()方法
    该方法的作用是加载存在已经激活的 profiles
    private void initializeProfiles() {
        // 默认配置文件为null,以便优先被处理,具有最小优先级
        this.profiles.add((Object)null);
        // 4.1.1 判断当前环境是否配置 spring.profiles.active属性
        // 也就是遍历环境中所有的属性源集合,查看是否有名称为 spring.profiles.active的属性源
        // 比如说,在命令行参数当中添加 --spring.profiles.active=dev,
        //        或配置系统属性 System.setProperty("spring.profiles.active","dev"),那么就会去创建一个dev的 profile
        // 如果没有,就返回空集;如果有,就添加到 activatedViaProperty集中
        Set<ConfigFileApplicationListener.Profile> activatedViaProperty = this.getProfilesFromProperty("spring.profiles.active");
        // 4.1.1 判断当前环境是否配置 spring.profiles.include属性
        // 也就是遍历环境中所有的属性源集合,查看是否有名称为 spring.profiles.include的属性源
        // 如果没有,就返回空集;如果有,就添加到 includedViaProperty集中
        Set<ConfigFileApplicationListener.Profile> includedViaProperty  = this.getProfilesFromProperty("spring.profiles.include");
        // 4.1.2 如果没有特别指定的话,就是 application.properties 和 application-default.properties配置
        // 如果特别指定的话,就是 application.properties 和 已经激活的 profile
        // 返回该环境其他显式激活的配置文件集,已经添加过了,就不会再重复添加(除了 spring.profiles.active 和 spring.profiles.include指定的配置以外 )
        List<ConfigFileApplicationListener.Profile> otherActiveProfiles = this.getOtherActiveProfiles(activatedViaProperty, includedViaProperty);
        // 将 otherActiveProfiles集添加到 profiles集当中
        this.profiles.addAll(otherActiveProfiles);
        // 将 includedViaProperty集添加到 profiles集当中
        this.profiles.addAll(includedViaProperty);
        // 4.1.3
        // 将 activatedViaProperty集添加到 profiles集中,以确保 spring.profiles.active指定的值生效
        // 同时移除默认配置
        this.addActiveProfiles(activatedViaProperty);
        // 如果 profiles集仍然为null,即没有指定,就会创建默认的profile
    !-- 这就说明了为什么 spring.profiles.active指定的配置文件会和 default配置文件互斥的原因 -- !
        if (this.profiles.size() == 1) {
            // 如果没有用 spring.profiles.default指定profile值,那么默认返回default
            String[] var4 = this.environment.getDefaultProfiles();
            int var5 = var4.length;
            
            // 遍历返回的默认值,依次添加到profiles集当中
            for(int var6 = 0; var6 < var5; ++var6) {
                String defaultProfileName = var4[var6];
                ConfigFileApplicationListener.Profile defaultProfile = new ConfigFileApplicationListener.Profile(defaultProfileName, true);
                this.profiles.add(defaultProfile);
            }
        }

    }
    
补充(initializeProfiles()方法里面的子方法阐述)
   4.1.1
   == getProfilesFromProperty("spring.profiles.active")方法 == 
   该方法的作用是遍历环境中的已加载的所有属性源,以获取其中 spring.profiles.active指定的值,作为profile值
   private Set<ConfigFileApplicationListener.Profile> getProfilesFromProperty(String profilesProperty) {
        // 判断当前环境的已加载的所有属性源是否包含名为 spring.profiles.active指定的属性源
        // 相比如通过命令行参数或者系统环境指定的 spring.profiles.active对应的值都会被扫描到
        if (!this.environment.containsProperty(profilesProperty)) {
            return Collections.emptySet(); // 一般情况下,返回空集
        } else {
            // 通过当前environment对象实例化Binder对象
            Binder binder = Binder.get(this.environment);
            // 遍历环境中所有的属性源集合,查看是否有名称为 profilesProperty的属性源
            Set<ConfigFileApplicationListener.Profile> profiles = this.getProfiles(binder, profilesProperty);
            return new LinkedHashSet(profiles);
        }
   }
   对Binder类进行补充说明
   Binder类是一个容器对象,其中绑定来自当前Environment对象的一个或多个ConfigurationPropertySources属性
   下面这个方法就看出,通过传入的environment对象,去获取所有ConfigurationPropertySource类型的属性源
   public static Binder get(Environment environment, BindHandler defaultBindHandler) {
        Iterable<ConfigurationPropertySource> sources = ConfigurationPropertySources.get(environment);
        PropertySourcesPlaceholdersResolver placeholdersResolver = new PropertySourcesPlaceholdersResolver(environment);
        return new Binder(sources, placeholdersResolver, (ConversionService)null, (Consumer)null, defaultBindHandler);
   }
   
   4.1.2
   == getOtherActiveProfiles(activatedViaProperty, includedViaProperty)方法 == 
   该方法的作用是获取其他显式配置激活的profile,之前添加的,不再重复添加
   private List<ConfigFileApplicationListener.Profile> getOtherActiveProfiles(Set<ConfigFileApplicationListener.Profile> activatedViaProperty, Set<ConfigFileApplicationListener.Profile> includedViaProperty) {
        // 从 activeProfiles集获取之前注册的激活profile
        return (List)Arrays.stream(this.environment.getActiveProfiles()).map(ConfigFileApplicationListener.Profile::new).filter((profile) -> {
            // 其中,filter()方法保存当前满足过滤条件的元素
            return !activatedViaProperty.contains(profile) && !includedViaProperty.contains(profile);
        }).collect(Collectors.toList());
   }
   
   4.1.3
   == addActiveProfiles(activatedViaProperty)方法 == 
   该方法的作用是将 activatedViaProperty集添加到 profiles队列中
     确保 spring.profiles.active指定的 profile会生效,也就是迭代的激活的 profiles会覆写默认的配置(队列)
   void addActiveProfiles(Set<ConfigFileApplicationListener.Profile> profiles) {
        if (!profiles.isEmpty()) {
            // 之前已经将 spring.profiles.active指定的profile添加进去,就不会再次添加
            // 判断激活标志是否为true
            // 也就是判断 spring.profiles.active指定的profile是否添加到 profiles队列当中
            if (this.activatedProfiles) {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Profiles already activated, '" + profiles + "' will not be applied");
                }
            
            // 如果之前没有添加,就将 spring.profiles.active指定的profile添加到 profiles队列当中
            // spring.profiles.active指定的 profile也就是 activatedViaProperty集
            } else {
                this.profiles.addAll(profiles);
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Activated activeProfiles " + StringUtils.collectionToCommaDelimitedString(profiles));
                }

                this.activatedProfiles = true; // 将激活标志置为false
                // 移除默认指定的 profile
                // 如果此 profile不为null,并且是 spring.profiles.default指定的 profile
                this.removeUnprocessedDefaultProfiles();
            }
        }
   }

4.2 进入 load(ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilterFactory filterFactory, ConfigFileApplicationListener.DocumentConsumer consumer)方法

  1. 获取配置文件的加载路径,如果 spring.config.location指定配置文件的路径,则以指定的为准;如果没有,查看 spring.config-addition.location有无指定额外的路径,如果有,路径为指定的加上默认的路径;如果都没有,则以默认的路径为准(file:./config/,file:./,classpath:/config/,classpath:/)
  2. 获取配置文件的前缀名,根据已有的信息构成完整前缀。判断 spring.config.name是否指定前缀的名称(name值),如果没有,默认为"application"。拼接成完整前缀,路径 + {name} + "-" + {profile}就是完整前缀。
  3. 使用PropertiesPropertySourceLoader和YamlPropertySourceLoader加载器去加载,以PropertiesPropertySourceLoader为例,添加相应的文件扩展名,尝试去加载,先生成配置文件的Resouce对象,解析后生成PropertySource对象,封装到ConfigFileApplicationListener.Document对象中
4.2 load(profile, this::getPositiveProfileFilter, this.addToLoaded(MutablePropertySources::addLast, false))
   该方法的作用是确定搜索范围,获取对应的配置文件名,并使用相应的加载器加载
   private void load(ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilterFactory filterFactory, ConfigFileApplicationListener.DocumentConsumer consumer) {
       // 4.2.1 获取加载配置文件的路径
       this.getSearchLocations().forEach((location) -> {
           // 判断指定的搜索范围是否是文件夹
           // 如果是文件夹,需要进一步搜索,找到相应的配置文件
           // 如果不是文件夹,说明有可能一次性提供配置文件,直接去加载即可
           boolean isFolder = location.endsWith("/");
           // 4.2.2 如果是文件夹,需要调用 getSearchNames()方法进一步找到配置文件
           // 如果没有用 spring.config.name指定配置文件的前缀,默认是返回"application"
           Set<String> names = isFolder ? this.getSearchNames() : ConfigFileApplicationListener.NO_SEARCH_NAMES;
           names.forEach((name) -> {
               // 4.2.3 加载相应路径下的配置文件,一般是 {name}-{profile}.(properties|yml)
               this.load(location, name, profile, filterFactory, consumer);
           });
       });
  }
  
4.2 补充(load(profile, filterFactory, consumer)方法里面的子方法阐述)
   4.2.1
   ## 检索路径 ##
   private Set<String> getSearchLocations() {
   该方法的作用是获取搜索范围,从以下三个角度
   1. spring.config.location 指定的路径
   2. spring.config.addition-location 指定的路径
   3. 默认路径(file:./config/,file:./,classpath:/config/,classpath:/)
       // 如果环境中有名为 spring.config.location的属性源
       // spring.config.location配置指定了搜索范围,则以它指定的为准
       if (this.environment.containsProperty("spring.config.location")) {
           // 获取 spring.config.location指定的搜索范围
           return this.getSearchLocations("spring.config.location");
       } else {
           // 获取 spring.config.additional-location指定的搜索范围
           Set<String> locations = this.getSearchLocations("spring.config.additional-location");
           // 将默认的搜索范围添加进去
           // 1. file:./config/
           // 2. file:./
           // 3. classpath:/config/
           // 4. classpath:/
           locations.addAll(this.asResolvedSet(ConfigFileApplicationListener.this.searchLocations, "classpath:/,classpath:/config/,file:./,file:./config/"));
           return locations; // 返回处理后的搜索范围
       }
   }
   
   private Set<String> getSearchLocations(String propertyName) {
   该方法的作用是从指定的值获取搜索范围
       Set<String> locations = new LinkedHashSet();
       String path;
       // 判断环境当中是否存在该属性
       if (this.environment.containsProperty(propertyName)) {
           // 如果存在该属性,则开始遍历解析后的值
           for(Iterator var3 = this.asResolvedSet(this.environment.getProperty(propertyName), (String)null).iterator(); var3.hasNext(); locations.add(path)) {
               path = (String)var3.next();
               // 如果路径不存在"$",一般是占位符
               if (!path.contains("$")) {
                   path = StringUtils.cleanPath(path);
                   // 如果路径不是以url形式表示,即只有提供相对路径
                   // 则添加前缀"file:",变成绝对路径,默认从文件系统加载
                   if (!ResourceUtils.isUrl(path)) {
                       path = "file:" + path;
                   }
                }
           }
       }

       return locations;
  }
  
  4.2.2
  ## 获取配置文件的前缀 ##  
  private Set<String> getSearchNames() {
  该方法的作用是获取配置文件的前缀中name对应的值
  即 {name}-{profile}.(properties|yml)前面的name值,一般默认是application
      // 如果环境中包含 spring.config.name指定的属性值
      if (this.environment.containsProperty("spring.config.name")) {
          // 获取 spirng.config.name指定的属性值
          String property = this.environment.getProperty("spring.config.name");
          // 返回 spirng.config.name指定的配置文件前缀
          return this.asResolvedSet(property, (String)null);
      } else {
          // 返回默认的配置文件前缀"application"
          return this.asResolvedSet(ConfigFileApplicationListener.this.names, "application");
      }
  }
  
  4.2.3
  ## 加载配置文件 ##
  private void load(String location, String name, ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilterFactory filterFactory, ConfigFileApplicationListener.DocumentConsumer consumer) {
  该方法的作用是针对配置文件的不同前缀,使用不同的方式进行相应的处理 
  此时,前缀等于location + name   
      // StringUtils.hasText(String str)方法是用来检查给定字符串是否包含实际文本
      // 也就是判断name值是否为""," ",null;一般默认值是"application",所以不会进入if语句块当中
      if (!StringUtils.hasText(name)) {
          Iterator var13 = this.propertySourceLoaders.iterator();

          PropertySourceLoader loader;
          do {
              if (!var13.hasNext()) {
                  throw new IllegalStateException("File extension of config file location '" + location + "' is not known to any PropertySourceLoader. If the location is meant to reference a directory, it must end in '/'");
              }

              loader = (PropertySourceLoader)var13.next();
          } while(!this.canLoadFileExtension(loader, location));

          this.load(loader, location, profile, filterFactory.getDocumentFilter(profile), consumer);
      } 
       // 针对"application"值,使用相应的属性资源加载器(前面构造Loader的时候已经初始化)进行处理
       // 其中,属性资源加载器有两种
       // 1. PropertiesPropertySourceLoader类 支持properties和xml文件,解析成Properties,然后封装成PropertiesPropertySource
       // 2. YamlPropertySourceLoader类 支持yml和yaml文件,解析成Map,然后封装成MapPropertySource
       else {
          Set<String> processed = new HashSet();
          // 获取迭代器
          Iterator var7 = this.propertySourceLoaders.iterator();
          
          while(var7.hasNext()) {
              // 获取属性资源加载器
              PropertySourceLoader loaderx = (PropertySourceLoader)var7.next();
              // 返回属性资源加载器可以支持的扩展名
              // PropertiesPropertySourceLoader加载器支持以"properties"、"xml"为后缀的配置文件
              // YamlPropertySourceLoader加载器支持以"yml"、"ymal"为后缀的配置文件
              String[] var9 = loaderx.getFileExtensions();
              int var10 = var9.length;

              for(int var11 = 0; var11 < var10; ++var11) {
                  String fileExtension = var9[var11];
                  if (processed.add(fileExtension)) {
                      this.loadForFileExtension(loaderx, location + name, "." + fileExtension, profile, filterFactory, consumer);
                  }
              }
         }

      }
   }
 
   private void loadForFileExtension(PropertySourceLoader loader, String prefix, String fileExtension, ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilterFactory filterFactory, ConfigFileApplicationListener.DocumentConsumer consumer) {
   该方法的作用是根据配置文件的绝对路径名(上面已经添加文件扩展名),来加载配置文件    
       ConfigFileApplicationListener.DocumentFilter defaultFilter = filterFactory.getDocumentFilter((ConfigFileApplicationListener.Profile)null);
       ConfigFileApplicationListener.DocumentFilter profileFilter = filterFactory.getDocumentFilter(profile);
       // 如果profile不为null的话,配置文件名是 {name}-{profile}.fileExtension
       // 比如遍历到第一个location,使用PropertiesPropertySourceLoader加载器加载时
       //     默认情况是 location:file:./config/,name:application,profile:default,fileExtension:properties
       //     此时的 prefix=file:./config/application,profile=default,fileExtension=properties
       //           profileSpecificFile=file:./config/application-default.properties
       if (profile != null) {
           // 确定配置文件的具体文件名(包括路径和完整的文件名)
           String profileSpecificFile = prefix + "-" + profile + fileExtension;
           this.load(loader, profileSpecificFile, profile, defaultFilter, consumer);
           this.load(loader, profileSpecificFile, profile, profileFilter, consumer);
           Iterator var10 = this.processedProfiles.iterator();

           while(var10.hasNext()) {
               ConfigFileApplicationListener.Profile processedProfile = (ConfigFileApplicationListener.Profile)var10.next();
               if (processedProfile != null) {
                   String previouslyLoaded = prefix + "-" + processedProfile + fileExtension;
                   this.load(loader, previouslyLoaded, profile, profileFilter, consumer);
               }
           }
       }

       this.load(loader, prefix + fileExtension, profile, profileFilter, consumer);
   }
   
   private void load(PropertySourceLoader loader, String location, ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilter filter, ConfigFileApplicationListener.DocumentConsumer consumer) {
   该方法的作用是将获取配置文件的Resouce对象,解析后生成PropertySource对象,封装到Document对象中    
       try {
           // 获取指定路径匹配的Resource实例
           Resource resource = this.resourceLoader.getResource(location);
           StringBuilder descriptionxx;
           // 如果存在Resource实例,并且不为null
           if (resource != null && resource.exists()) {
               // getFilename()方法返回资源的文件名
               // getFilenameExtension(String path)方法从给定的资源路径获取扩展文件名
               // 一般就是属性资源加载器所支持的 fileExtension,比如"properties"、"xml"、"yml"、"yaml"
               // 判断配置文件的后缀是否存在,如果不存在,会打印日志堆栈信息,方便追踪调试
               if (!StringUtils.hasText(StringUtils.getFilenameExtension(resource.getFilename()))) {
                   if (this.logger.isTraceEnabled()) {
                       descriptionxx = this.getDescription("Skipped empty config extension ", location, resource, profile);
                       this.logger.trace(descriptionxx); // 打印日志信息
                   }

               } else {
                   // 此时name:applicationConfig:[profileSpecificFile]
                   // 比如applicationConfig[file:./config/application-default.properties]
                   String name = "applicationConfig: [" + location + "]";
                   List<ConfigFileApplicationListener.Document> documents = this.loadDocuments(loader, name, resource);
                   if (CollectionUtils.isEmpty(documents)) {
                       if (this.logger.isTraceEnabled()) {
                           StringBuilder description = this.getDescription("Skipped unloaded config ", location, resource, profile);
                           this.logger.trace(description);
                       }

                   } else {
                       List<ConfigFileApplicationListener.Document> loaded = new ArrayList();
                       Iterator var10 = documents.iterator();

                       while(var10.hasNext()) {
                           ConfigFileApplicationListener.Document document = (ConfigFileApplicationListener.Document)var10.next();
                           if (filter.match(document)) {
                               this.addActiveProfiles(document.getActiveProfiles());
                               this.addIncludedProfiles(document.getIncludeProfiles());
                               loaded.add(document);
                           }
                       }

                       Collections.reverse(loaded);
                       if (!loaded.isEmpty()) {
                           loaded.forEach((documentx) -> {
                               consumer.accept(profile, documentx);
                           });
                           if (this.logger.isDebugEnabled()) {
                               StringBuilder descriptionx = this.getDescription("Loaded config file ", location, resource, profile);
                               this.logger.debug(descriptionx);
                           }
                       }

                   }
               }
           } else {
               if (this.logger.isTraceEnabled()) {
                   descriptionxx = this.getDescription("Skipped missing config ", location, resource, profile);
                   this.logger.trace(descriptionxx);
               }

           }
       } catch (Exception var12) {
           throw new IllegalStateException("Failed to load property source from location '" + location + "'", var12);
       }
   }

- End -(转载请注明出处)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档