首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >「Spring 源码分析」Profile

「Spring 源码分析」Profile

原创
作者头像
花言不知梦
修改于 2020-05-18 03:17:15
修改于 2020-05-18 03:17:15
1.1K00
代码可运行
举报
文章被收录于专栏:花言不知梦花言不知梦
运行总次数:0
代码可运行

Profile

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

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

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

  1. 更新 profiles集,添加存在已经激活的profile值,如果不存在,添加默认指定的profile值到profiles集当中
  2. 确定搜索范围(路径),获取配置文件名({name}-{profile}),使用PropertiesPropertySourceLoader和YamlPropertySourceLoader这两个加载器添加相应的文件扩展名,进行加载
  3. 将加载后的loaded列表逆序,遍历该列表中的每一个MutablePropertySources对象,依次注入到environment对象的propertySources属性值当中,这里就意味着完成profile所指定的一组bean的注册工作
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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"
代码语言:java
AI代码解释
复制
 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对象中
代码语言:java
AI代码解释
复制
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 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
SpringBoot Profile使用详解及配置源码解析
Profile对应中文并没有合适的翻译,它的主要作用就是让Spring Boot可以根据不同环境提供不同的配置功能支持。
程序新视界
2019/12/26
1.5K0
SpringBoot启动流程(四)application配置文件加载过程
在上一篇文章中,我们看到了Environment对象的创建方法。同时也稍微提及了一下ConfigFileApplicationListener这个监听器,这个监听器主要工作是为了加载application.properties/yml配置文件的。
技术从心
2021/02/03
1K0
SpringBoot启动流程(四)application配置文件加载过程
Apollo与SpringBoot整合原理深度剖析
AbstractBeanFactory的embeddedValueResolvers集合中StringValueResolver 的注册时机是什么呢?
大忽悠爱学习
2023/05/23
1.2K0
Apollo与SpringBoot整合原理深度剖析
源码解读 Spring Boot Profiles
上文《一文掌握 Spring Boot Profiles》 是对 Spring Boot Profiles 的介绍和使用,因此本文将从源码角度探究 Spring Boot Profiles,让我们看下 Spring Boot 底层是如何应用 Profiles 进行环境配置的隔离与生效的。
闻人的技术博客
2019/09/19
5030
源码解读 Spring Boot Profiles
SpringBoot源码分析 顶
一:创建SpringApplication对象过程:new SpringApplication(primarySources)
须臾之余
2019/11/07
6020
SpringBoot源码分析
                                                                            顶
原 荐 SpringBoot 2.0 系列0
SpringBoot 2.0 系列004 --启动实战之配置文件 配置文件 配置文件加载流程 很多文档包括官方文档说SB的默认配置文件是application开头的文件,那么是为什么呢? 我们先
石奈子
2018/06/13
9090
SpringBoot源码学习(一)
工作中对于我们java开发者来说最经常使用的框架就是spring了,那么了解spring的基础原理对于我们的能力提升具有很大的好处。首先,作为框架首先它肯定还是从java基础演变而来,也就是说框架的代码都是基于我们日常使用的继承、多态已经各种设计模式的整合而抽取出来的一套规范。我们开发项目要想搭乘spring的快车就需要按规范做事,按规范开发。那么规范的熟悉程度就等价于项目质量的高低。当然框架的基础都是好的idea,好的idea不仅兼容一切还简单。这就和物理界的大一统理论一样。怎么做不重要,重要的是怎么兼容一切,因为做的办法会有无限种。实在无法实现也可以同缩小解的范围。废话不说了。让我们开启spring的流浪之旅。
写一点笔记
2020/09/10
6230
【Spring Boot 四】启动之准备系统环境environmentPrepared
SpringBoot启动的时候 listeners.starting() ;接下来就是准备环境的过程
石臻臻的杂货铺[同名公众号]
2021/07/14
9810
SpringBoot 实践-配置优先级
除了 application.properties 文件之外,profile-specific 配置也可以通过以下命名方式来定义:application-{profile}.properties。在没有使用 active 指定 profiles 的情况下,Environment 会指定一组默认的 profiles(默认情况下是[default]),换句话说就是,如果没有显示的激活 profiles 配置文件,则默认加载的是 application-default.properties 配置文件。
磊叔的技术博客
2025/06/07
1300
SpringBoot 实践-配置优先级
基于SpringBoot的Environment源码理解实现分散配置
org.springframework.core.env.Environment是当前应用运行环境的公开接口,主要包括应用程序运行环境的两个关键方面:配置文件(profiles)和属性。Environment继承自接口PropertyResolver,而PropertyResolver提供了属性访问的相关方法。这篇文章从源码的角度分析Environment的存储容器和加载流程,然后基于源码的理解给出一个生产级别的扩展。
Throwable
2020/06/23
2K0
Springboot之ConfigFileApplicationListener
                                                                                     图1
克虏伯
2019/08/06
1K0
Springboot之ConfigFileApplicationListener
应用配置管理,基础原理分析
在微服务的代码工程中,配置管理是一项复杂的事情,即需要做好各个环境的配置隔离措施,还需要确保生产环境的配置安全;如果划分的微服务足够的多,还要考虑配置更新时的效率;
知了一笑
2022/11/30
4900
应用配置管理,基础原理分析
SpringBoot源码之属性文件加载原理剖析
  首先我们来看一个问题。就是我们在创建SpringBoot项目的时候会在对应的application.properties或者application.yml文件中添加对应的属性信息,我们的问题是这些属性文件是什么时候被加载的?如果要实现自定义的属性文件怎么来实现呢?本文来给大家揭晓答案:
用户4919348
2022/01/07
4270
SpringBoot源码之属性文件加载原理剖析
spring-boot-2.0.3不一样系列之源码篇 - run方法(二)之prepareEnvironment,绝对有值得你看的地方
  此系列是针对springboot的启动,旨在于和大家一起来看看springboot启动的过程中到底做了一些什么事。如果大家对springboot的源码有所研究,可以挑些自己感兴趣或者对自己有帮助的看;但是如果大家没有研究过springboot的源码,不知道springboot在启动过程中做了些什么,那么我建议大家从头开始一篇一篇按顺序读该系列,不至于从中途插入,看的有些懵懂。当然,文中讲的不对的地方也欢迎大家指出,有待改善的地方也希望大家不吝赐教。老规矩:一周至少一更,中途会不定期的更新一些其他的博客,可能是springboot的源码,也可能是其他的源码解析,也有可能是其他的。
青石路
2018/10/10
1.4K2
spring-boot-2.0.3不一样系列之源码篇 - run方法(二)之prepareEnvironment,绝对有值得你看的地方
SpringBoot读取配置文件源码探究
继续,重点是invokeListener方法,去调用监听器事件,可以想象对配置文件来讲,这就是读取配置事件了。同时监听器有很多,读取配置文件的监听器是ConfigFileAplicationListener,看名字还是蛮明显的吧
老梁
2019/08/29
3.1K0
聊聊Spring的环境抽象Environment,以及配置@Profile使用详解(介绍profile的6种激活方式)【享学Spring】
在我刚入行不久时,总是对上下文(Context)、环境(Environment)这类抽象概念搞不清楚、弄不明白、玩不转,更是不懂它哥俩的区别或者说是联系(说实话从中文上来说不好区分,至少我是这么认为的)。 直到现在,我可以根据自己的理解对这两者下个通俗易懂的定义(不喜勿喷):
YourBatman
2019/09/03
2.8K0
聊聊Spring的环境抽象Environment,以及配置@Profile使用详解(介绍profile的6种激活方式)【享学Spring】
Spring Boot 2.4 配置文件将加载机制大变化
Spring Boot 2.4.0.M2 刚刚发布,它对 application.properties 和 application.yml 文件的加载方式进行重构。如果应用程序仅使用单个 application.properties 或 application.yml 作为配置文件,那么可能感受不到任何区别。但是如果您的应用程序使用更复杂的配置(例如,Spring Cloud 配置中心等),则需要来了解更改的内容以及原因。
冷冷
2020/10/12
1.6K0
补习系列(22)-全面解读 Spring Profile 的用法
Spring框架提供了多profile的管理功能,我们可以使用profile功能来区分不同环境的配置。
美码师
2019/07/30
1.1K0
spring boot 之 profile 配置
SPRING Environment 为此提供了一个 API,但是您通常会设置一个 System 属性(spring.profiles.active) 或者一个 OS 环境变量(SPRING_PROFILES_ACTIVE)。此外,您可以使用 -d 参数启动应用程序(记住将其放在 main 类或 jar 归档之前) ,如下所示:
acc8226
2022/09/21
8110
SpringBoot入门建站全系列(二十三)配置文件优先级及常用配置方式
Spring Boot使用一种非常特殊的PropertySource顺序,旨在允许合理地覆盖值。按以下顺序考虑属性(优先级从高到低):
品茗IT
2019/09/12
1K0
相关推荐
SpringBoot Profile使用详解及配置源码解析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验