欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot中實(shí)現(xiàn)加載遠(yuǎn)程配置的代碼示例

 更新時間:2023年06月04日 08:37:33   作者:西直門三太子  
本文章將通過結(jié)合consul config來講解在springboot中如何加載遠(yuǎn)程配置:通過consul config加載consul server中存儲的配置,需要的朋友可以參考下

加載配置文件方式

對于一個工程來說,我們一般都會需要有各種配置,在spring工程里面,一般都是yml或者properties文件,如下所示:

server:
  port: 9991 # 端口
spring:
  application:
    name: ts-service1 # 應(yīng)用名稱
  profiles:
    active: dev # 指定環(huán)境,默認(rèn)加載 default 環(huán)境
  cloud:
    consul:
      # Consul 服務(wù)器地址
      host: 51.6.196.200
      port: 8500
      # 配置中心相關(guān)配置
      config:
        # 是否啟用配置中心,默認(rèn)值 true 開啟
        enabled: true
        # 設(shè)置配置的基本文件夾,默認(rèn)值 config 可以理解為配置文件所在的最外層文件夾
        prefix: config
        # 設(shè)置應(yīng)用的文件夾名稱,默認(rèn)值 application 一般建議設(shè)置為微服務(wù)應(yīng)用名稱
        default-context: tsService
        # 配置環(huán)境分隔符,默認(rèn)值 "," 和 default-context 配置項(xiàng)搭配
        # 例如應(yīng)用 orderService 分別有環(huán)境 default、dev、test、prod
        # 只需在 config 文件夾下創(chuàng)建 orderService、orderService-dev、orderService-test、orderService-prod 文件夾即可
        profile-separator: '-'
        # 指定配置格式為 yaml
        format: YAML
        # Consul 的 Key/Values 中的 Key,Value 對應(yīng)整個配置文件
        data-key: redisConfig
        # 以上配置可以理解為:加載 config/orderService/ 文件夾下 Key 為 orderServiceConfig 的 Value 對應(yīng)的配置信息
        watch:
          # 是否開啟自動刷新,默認(rèn)值 true 開啟
          enabled: true
          # 刷新頻率,單位:毫秒,默認(rèn)值 1000
          delay: 1000
      # 服務(wù)發(fā)現(xiàn)相關(guān)配置
      discovery:
        register: true                                # 是否需要注冊
        instance-id: ${spring.application.name}-01    # 注冊實(shí)例 id(必須唯一)
        service-name: ${spring.application.name}      # 服務(wù)名稱
        port: ${server.port}                          # 服務(wù)端口
        prefer-ip-address: true                       # 是否使用 ip 地址注冊
        ip-address: ${spring.cloud.client.ip-address} # 服務(wù)請求 ip

那么對于讀取這些配置文件中的值,一般有如下幾種方式

  • 1、使用 @Value("${property}") 讀取比較簡單的配置信息。
  • 2、通過@ConfigurationProperties讀取并通過@Component與 bean 綁定
  • 3、通過@ConfigurationProperties讀取并在使用的地方使用@EnableConfigurationProperties注冊需要的配置 bean
  • 4、通過@PropertySource讀取指定 properties 文件

注:spring加載配置文件有個默認(rèn)的加載順序的,根據(jù)存放的路徑來決定。

拉取遠(yuǎn)程配置

我們知道,上面說的那些一般要求配置都必須是本地,而且格式只能是 properties(或者 yaml)。那么,如果我們有遠(yuǎn)程配置,如何把他引入進(jìn)來來呢。主要有以下三步:

  • 1、編寫PropertySource:編寫一個類繼承EnumerablePropertySource,然后實(shí)現(xiàn)它的抽象方法即可。
  • 2、編寫PropertySourceLocator:PropertySourceLocator 其實(shí)就是用來定位我們前面的PropertySource,需要重寫的方法只有一個,就是返回一個PropertySource對象。
  • 3、配置PropertySourceLocator生效

下面就以consul為例,剖析下它是怎么做的

consul的配置示例如下:

spring:
  application:
    name: ts-service1 # 應(yīng)用名稱
  profiles:
    active: dev # 指定環(huán)境,默認(rèn)加載 default 環(huán)境
  cloud:
    consul:
      # Consul 服務(wù)器地址
      host: 51.6.196.200
      port: 8500
      # 配置中心相關(guān)配置
      config:
        # 是否啟用配置中心,默認(rèn)值 true 開啟
        enabled: true
        # 設(shè)置配置的基本文件夾,默認(rèn)值 config 可以理解為配置文件所在的最外層文件夾
        prefix: config
        # 設(shè)置應(yīng)用的文件夾名稱,默認(rèn)值 application 一般建議設(shè)置為微服務(wù)應(yīng)用名稱
        default-context: tsService
        # 配置環(huán)境分隔符,默認(rèn)值 "," 和 default-context 配置項(xiàng)搭配
        # 例如應(yīng)用 orderService 分別有環(huán)境 default、dev、test、prod
        # 只需在 config 文件夾下創(chuàng)建 orderService、orderService-dev、orderService-test、orderService-prod 文件夾即可
        profile-separator: '-'
        # 指定配置格式為 yaml
        format: YAML
        # Consul 的 Key/Values 中的 Key,Value 對應(yīng)整個配置文件
        data-key: redisConfig
        # 以上配置可以理解為:加載 config/orderService/ 文件夾下 Key 為 orderServiceConfig 的 Value 對應(yīng)的配置信息
        watch:
          # 是否開啟自動刷新,默認(rèn)值 true 開啟
          enabled: true
          # 刷新頻率,單位:毫秒,默認(rèn)值 1000
          delay: 1000

一般對于配置文件,都有一個對應(yīng)的配置屬性類,consul也不例外:

@ConfigurationProperties("spring.cloud.consul.config")
@Validated
public class ConsulConfigProperties {
  private boolean enabled = true;
  private String prefix = "config";
  @NotEmpty
  private String defaultContext = "application";
  @NotEmpty
  private String profileSeparator = ",";
  @NotNull
  private Format format = Format.KEY_VALUE;
  /**
   * If format is Format.PROPERTIES or Format.YAML then the following field is used as
   * key to look up consul for configuration.
   */
  @NotEmpty
  private String dataKey = "data";
  @Value("${consul.token:${CONSUL_TOKEN:${spring.cloud.consul.token:${SPRING_CLOUD_CONSUL_TOKEN:}}}}")
  private String aclToken;
  private Watch watch = new Watch();
  ...
}

上面代碼對應(yīng)的就是yml文件中***spring.consul.config***下面的這一部分的配置。

1、編寫PropertySource

consul config下面有這樣一個類:ConsulPropertySource,看下它的繼承關(guān)系:

public class ConsulPropertySource extends EnumerablePropertySource<ConsulClient> {
  private final Map<String, Object> properties = new LinkedHashMap<>();
}

可以看到,它使用了一個map來說存儲配置數(shù)據(jù)。

主要看下以下三個方法:

@Override
public Object getProperty(String name) {
  return this.properties.get(name);
}
@Override
public String[] getPropertyNames() {
  Set<String> strings = this.properties.keySet();
  return strings.toArray(new String[strings.size()]);
}

這兩個方法就是需要繼承實(shí)現(xiàn)的父類方法,主要就是獲取配置信息,那這些配置信息是哪里來的呢?下面看第三個方法:

public void init() {
  if (!this.context.endsWith("/")) {
    this.context = this.context + "/";
  }
  Response<List<GetValue>> response = this.source.getKVValues(this.context,
      this.configProperties.getAclToken(), QueryParams.DEFAULT);
  this.initialIndex = response.getConsulIndex();
  final List<GetValue> values = response.getValue();
  ConsulConfigProperties.Format format = this.configProperties.getFormat();
  switch (format) {
  case KEY_VALUE:
    parsePropertiesInKeyValueFormat(values);
    break;
  case PROPERTIES:
  case YAML:
    parsePropertiesWithNonKeyValueFormat(values, format);
  }
}

這里的this.context可以理解為consul中key-value存儲里面的key。this.source就是ConsulClient。

上面代碼的邏輯就是:

  • 通過consulclient向consul server發(fā)起請求,查詢前綴key為this.context的value信息
  • 根據(jù)consul配置文件(也就是工程里面的yml或者properties文件)里面配置的format配置來決定解析該response
  • 如果format是key-value,則表示consule server中該this.context對應(yīng)的value是一個key-value格式的值,按照key-value進(jìn)行解析放入this.properties中
  • 如果format是yml或者properties,則表示consule server中該this.context對應(yīng)的value是一個yml或者properties格式的值,按照相應(yīng)的格式進(jìn)行解析放入this.properties中

注:consul config還提供了另外一個propertySource的實(shí)現(xiàn):

public class ConsulFilesPropertySource extends ConsulPropertySource {
  public void init(GetValue value) {
    if (this.getContext().endsWith(".yml") || this.getContext().endsWith(".yaml")) {
      parseValue(value, YAML);
    }
    else if (this.getContext().endsWith(".properties")) {
      parseValue(value, PROPERTIES);
    }
    else {
      throw new IllegalStateException(
          "Unknown files extension for context " + this.getContext());
    }
  }
}

該類繼承自上面說的那個類,實(shí)現(xiàn)了init方法:主要就是用于直接將獲取到的value根據(jù)需要解析成yml或者properties格式的數(shù)據(jù)。

2、編寫PropertySourceLocator

consul config的實(shí)現(xiàn)類如下:

@Order(0)
public class ConsulPropertySourceLocator implements PropertySourceLocator {}

如上面所說,我們主要關(guān)注下locate方法:

@Override
@Retryable(interceptor = "consulRetryInterceptor")
public PropertySource<?> locate(Environment environment) {
  if (environment instanceof ConfigurableEnvironment) {
    ConfigurableEnvironment env = (ConfigurableEnvironment) environment;
    String appName = this.properties.getName();
    if (appName == null) {
      appName = env.getProperty("spring.application.name");
    }
    List<String> profiles = Arrays.asList(env.getActiveProfiles());
    String prefix = this.properties.getPrefix();
    List<String> suffixes = new ArrayList<>();
    if (this.properties.getFormat() != FILES) {
      suffixes.add("/");
    }
    else {
      suffixes.add(".yml");
      suffixes.add(".yaml");
      suffixes.add(".properties");
    }
    String defaultContext = getContext(prefix,
        this.properties.getDefaultContext());
    for (String suffix : suffixes) {
      this.contexts.add(defaultContext + suffix);
    }
    for (String suffix : suffixes) {
      addProfiles(this.contexts, defaultContext, profiles, suffix);
    }
    String baseContext = getContext(prefix, appName);
    for (String suffix : suffixes) {
      this.contexts.add(baseContext + suffix);
    }
    for (String suffix : suffixes) {
      addProfiles(this.contexts, baseContext, profiles, suffix);
    }
    Collections.reverse(this.contexts);
    CompositePropertySource composite = new CompositePropertySource("consul");
    for (String propertySourceContext : this.contexts) {
      try {
        ConsulPropertySource propertySource = null;
        if (this.properties.getFormat() == FILES) {
          Response<GetValue> response = this.consul.getKVValue(
              propertySourceContext, this.properties.getAclToken());
          addIndex(propertySourceContext, response.getConsulIndex());
          if (response.getValue() != null) {
            ConsulFilesPropertySource filesPropertySource = new ConsulFilesPropertySource(
                propertySourceContext, this.consul, this.properties);
            filesPropertySource.init(response.getValue());
            propertySource = filesPropertySource;
          }
        }
        else {
          propertySource = create(propertySourceContext, this.contextIndex);
        }
        if (propertySource != null) {
          composite.addPropertySource(propertySource);
        }
      }
      catch (Exception e) {
        if (this.properties.isFailFast()) {
          log.error(
              "Fail fast is set and there was an error reading configuration from consul.");
          ReflectionUtils.rethrowRuntimeException(e);
        }
        else {
          log.warn("Unable to load consul config from "
              + propertySourceContext, e);
        }
      }
    }
    return composite;
  }
  return null;
}

上面代碼的邏輯就是:

  • 通過上面配置文件中prefix和default-context、prefix和application.name通過分隔符組合成consule中的key
  • 對每一個key,創(chuàng)建ConsulPropertySource實(shí)例并初始化(上一節(jié)我們已經(jīng)分析過了),將該實(shí)例保存下來

3、配置啟動加載

consul config實(shí)現(xiàn)這樣一個類:

@Configuration(proxyBeanMethods = false)
@ConditionalOnConsulEnabled
public class ConsulConfigBootstrapConfiguration {
  @Configuration(proxyBeanMethods = false)
  @EnableConfigurationProperties
  @Import(ConsulAutoConfiguration.class)
  @ConditionalOnProperty(name = "spring.cloud.consul.config.enabled",
      matchIfMissing = true)
  protected static class ConsulPropertySourceConfiguration {
    @Autowired
    private ConsulClient consul;
    @Bean
    @ConditionalOnMissingBean
    public ConsulConfigProperties consulConfigProperties() {
      return new ConsulConfigProperties();
    }
    @Bean
    public ConsulPropertySourceLocator consulPropertySourceLocator(
        ConsulConfigProperties consulConfigProperties) {
      return new ConsulPropertySourceLocator(this.consul, consulConfigProperties);
    }
  }
}

然后在 META-INF/spring.factories中配置如下:

# Auto Configuration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.consul.config.ConsulConfigAutoConfiguration
# Bootstrap Configuration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.consul.config.ConsulConfigBootstrapConfiguration

就是給Spring Boot說,這個是一個啟動配置類,spring boot在啟動的時候會自動加載。

放入environment

上面講解了對應(yīng)接口的實(shí)現(xiàn),那么consul的這些實(shí)現(xiàn)類是在哪里調(diào)用的呢?

過程是這樣的:spring boot工程在啟動的時候,會執(zhí)行BootStrapConfiguration的initize方法,PropertySourceBootstrapConfiguration的該方法如下:

@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
  List<PropertySource<?>> composite = new ArrayList<>();
  AnnotationAwareOrderComparator.sort(this.propertySourceLocators);
  boolean empty = true;
  ConfigurableEnvironment environment = applicationContext.getEnvironment();
  for (PropertySourceLocator locator : this.propertySourceLocators) {
    Collection<PropertySource<?>> source = locator.locateCollection(environment);
    if (source == null || source.size() == 0) {
      continue;
    }
    List<PropertySource<?>> sourceList = new ArrayList<>();
    for (PropertySource<?> p : source) {
      if (p instanceof EnumerablePropertySource) {
        EnumerablePropertySource<?> enumerable = (EnumerablePropertySource<?>) p;
        sourceList.add(new BootstrapPropertySource<>(enumerable));
      }
      else {
        sourceList.add(new SimpleBootstrapPropertySource(p));
      }
    }
    logger.info("Located property source: " + sourceList);
    composite.addAll(sourceList);
    empty = false;
  }
  if (!empty) {
    MutablePropertySources propertySources = environment.getPropertySources();
    String logConfig = environment.resolvePlaceholders("${logging.config:}");
    LogFile logFile = LogFile.get(environment);
    for (PropertySource<?> p : environment.getPropertySources()) {
      if (p.getName().startsWith(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
        propertySources.remove(p.getName());
      }
    }
    insertPropertySources(propertySources, composite);
    reinitializeLoggingSystem(environment, logConfig, logFile);
    setLogLevels(applicationContext, environment);
    handleIncludedProfiles(environment);
  }
}

可以看到,這里代碼中,調(diào)用了每個PropertySourceLocator的實(shí)例方法locateCollection,該方法里面調(diào)用了locate方法,也就是回到了上一節(jié)所說的內(nèi)容了。最后將所有的source放入了environment中: insertPropertySources(propertySources, composite);

讀取propertySource

通過上面的方式加載了遠(yuǎn)程配置之后,我們在其他地方就可以任意讀取了,方式如下:

//可以獲取整個系統(tǒng)所有的配置:通過這個可以獲取到更新之前的數(shù)據(jù)
ConfigurableEnvironment environment = (ConfigurableEnvironment)context.getEnvironment();
PropertySources sources = environment.getPropertySources();

以上就是SpringBoot中實(shí)現(xiàn)加載遠(yuǎn)程配置的代碼示例的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot加載遠(yuǎn)程配置的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java中&和&&的基本區(qū)別與常見的誤用

    java中&和&&的基本區(qū)別與常見的誤用

    &?和&&是Java中用于邏輯運(yùn)算的兩個運(yùn)算符,&是按位與和邏輯與兼用的運(yùn)算符,而&&僅用于邏輯與運(yùn)算,并具有短路特性,這篇文章主要介紹了java中&和&&的基本區(qū)別與常見的誤用,需要的朋友可以參考下
    2025-02-02
  • JavaWeb實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)(1)

    JavaWeb實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)(1)

    這篇文章主要為大家詳細(xì)介紹了JavaWeb實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)第一篇,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • java枚舉enum和Enum類的使用

    java枚舉enum和Enum類的使用

    本文主要介紹了java枚舉enum和Enum類的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • 詳解Spring Boot中MyBatis的使用方法

    詳解Spring Boot中MyBatis的使用方法

    mybatis初期使用比較麻煩,需要各種配置文件、實(shí)體類、dao層映射關(guān)聯(lián)、還有一大推其它配置。當(dāng)然mybatis也發(fā)現(xiàn)了這種弊端。下面通過本文給大家詳細(xì)介紹Spring Boot中MyBatis的使用方法,感興趣的朋友一起看看吧
    2017-07-07
  • Java?InheritableThreadLocal使用示例詳解

    Java?InheritableThreadLocal使用示例詳解

    InheritableThreadLocal繼承了ThreadLocal,此類擴(kuò)展了ThreadLocal以提供從父線程到子線程的值的繼承:當(dāng)創(chuàng)建子線程時,子線程接收父線程具有的所有可繼承線程局部變量的初始值。?通常子線程的值與父線程的值是一致的
    2022-09-09
  • Dubbo負(fù)載均衡策略介紹

    Dubbo負(fù)載均衡策略介紹

    負(fù)載均衡改善了跨多個計(jì)算資源(例如計(jì)算機(jī),計(jì)算機(jī)集群,網(wǎng)絡(luò)鏈接,中央處理單元或磁盤驅(qū)動的的工作負(fù)載分布。負(fù)載平衡旨在優(yōu)化資源使用,最大化吞吐量,最小化響應(yīng)時間,并避免任何單個資源的過載
    2022-09-09
  • 詳解SpringBoot如何實(shí)現(xiàn)整合微信登錄

    詳解SpringBoot如何實(shí)現(xiàn)整合微信登錄

    本文主要介紹了SpringBoot實(shí)現(xiàn)整合微信登錄的過程詳解,文中的示例代碼介紹的非常詳細(xì),對我們的學(xué)習(xí)過工作有一定的參考價值,需要的朋友可以關(guān)注下
    2021-12-12
  • Mybatis查詢語句結(jié)果集的總結(jié)大全

    Mybatis查詢語句結(jié)果集的總結(jié)大全

    這篇文章主要給大家總結(jié)介紹了關(guān)于Mybatis查詢語句結(jié)果集的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08
  • Spring bean 四種注入方式詳解

    Spring bean 四種注入方式詳解

    這篇文章主要介紹了Spring bean的實(shí)例化和IOC依賴注入詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2021-07-07
  • maven中央倉庫修改驗(yàn)證方式導(dǎo)致用戶名密碼失效的解決方式

    maven中央倉庫修改驗(yàn)證方式導(dǎo)致用戶名密碼失效的解決方式

    這篇文章主要介紹了maven中央倉庫修改驗(yàn)證方式導(dǎo)致用戶名密碼失效的解決方式,文中通過圖文結(jié)合的方式講解的非常詳細(xì),對大家解決問題有一定的幫助
    2024-11-11

最新評論