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

apollo更改配置刷新@ConfigurationProperties配置類

 更新時間:2023年04月06日 15:18:41   作者:王者之峰  
這篇文章主要為大家介紹了apollo更改配置刷新@ConfigurationProperties配置類示例解析,apollo更改配置刷新@ConfigurationProperties配置類

前言

apollo配置經(jīng)常使用的方式是@value,比較便捷,如果只出現(xiàn)在一個類中還行,但是如果多個類中并不是很方便,特別是如果出現(xiàn)配置值變化了之后需要觸發(fā)相關(guān)變動也無法實現(xiàn),因此就會考慮使用配置類@ConfigurationProperties,它能實現(xiàn):

  • 統(tǒng)一管理一組配置。
  • 配置變化的時需要觸發(fā)相關(guān)變動只涉及一個bean。

但是apollo配置變化時不會把@ConfigurationProperties的值進行更新,具體看官方文檔,需要配合EnvironmentChangeEventRefreshScope使用。

可以大概看看:

package com.ctrip.framework.apollo.use.cases.spring.cloud.zuul;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.cloud.netflix.zuul.RoutesRefreshedEvent;
import org.springframework.cloud.netflix.zuul.filters.RouteLocator;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class ZuulPropertiesRefresher implements ApplicationContextAware {
  private static final Logger logger = LoggerFactory.getLogger(ZuulPropertiesRefresher.class);
  private ApplicationContext applicationContext;
  @Autowired
  private RouteLocator routeLocator;
  @ApolloConfigChangeListener(interestedKeyPrefixes = "zuul.")
  public void onChange(ConfigChangeEvent changeEvent) {
    refreshZuulProperties(changeEvent);
  }
  private void refreshZuulProperties(ConfigChangeEvent changeEvent) {
    logger.info("Refreshing zuul properties!");
    /**
     * rebind configuration beans, e.g. ZuulProperties
     * @see org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder#onApplicationEvent
     */
    this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));
    /**
     * refresh routes
     * @see org.springframework.cloud.netflix.zuul.ZuulServerAutoConfiguration.ZuulRefreshListener#onApplicationEvent
     */
    this.applicationContext.publishEvent(new RoutesRefreshedEvent(routeLocator));
    logger.info("Zuul properties refreshed!");
  }
  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.applicationContext = applicationContext;
  }
}

使用@ApolloConfigChangeListener注冊了apollo配置變化監(jiān)聽器,內(nèi)部使用了cloud發(fā)布EnvironmentChangeEvent事件進行更新。

/*
 * Copyright 2022 Apollo Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package com.apolloconfig.apollo.demo.springboot.refresh;
import com.apolloconfig.apollo.demo.springboot.config.SampleRedisConfig;
import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.context.scope.refresh.RefreshScope;
import org.springframework.stereotype.Component;
@ConditionalOnProperty("redis.cache.enabled")
@Component
public class SpringBootApolloRefreshConfig {
  private static final Logger logger = LoggerFactory.getLogger(SpringBootApolloRefreshConfig.class);
  private final SampleRedisConfig sampleRedisConfig;
  private final RefreshScope refreshScope;
  public SpringBootApolloRefreshConfig(
      final SampleRedisConfig sampleRedisConfig,
      final RefreshScope refreshScope) {
    this.sampleRedisConfig = sampleRedisConfig;
    this.refreshScope = refreshScope;
  }
  @ApolloConfigChangeListener(value = "${listeners}", interestedKeyPrefixes = {"redis.cache."})
  public void onChange(ConfigChangeEvent changeEvent) {
    logger.info("before refresh {}", sampleRedisConfig.toString());
    refreshScope.refresh("sampleRedisConfig");
    logger.info("after refresh {}", sampleRedisConfig);
  }
}
/*
 * Copyright 2022 Apollo Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package com.apolloconfig.apollo.demo.springboot.config;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
/**
 * You may set up data like the following in Apollo: <br /><br /> Properties Sample:
 * application.properties
 * <pre>
 * redis.cache.enabled = true
 * redis.cache.expireSeconds = 100
 * redis.cache.clusterNodes = 1,2
 * redis.cache.commandTimeout = 50
 * redis.cache.someMap.key1 = a
 * redis.cache.someMap.key2 = b
 * redis.cache.someList[0] = c
 * redis.cache.someList[1] = d
 * </pre>
 *
 * Yaml Sample: application.yaml
 * <pre>
 * redis:
 *   cache:
 *     enabled: true
 *     expireSeconds: 100
 *     clusterNodes: 1,2
 *     commandTimeout: 50
 *     someMap:
 *       key1: a
 *       key2: b
 *     someList:
 *     - c
 *     - d
 * </pre>
 *
 * To make <code>@ConditionalOnProperty</code> work properly, <code>apollo.bootstrap.enabled</code>
 * should be set to true and <code>redis.cache.enabled</code> should also be set to true. Check
 * 'src/main/resources/application.yml' for more information.
 *
 */
@ConditionalOnProperty("redis.cache.enabled")
@ConfigurationProperties(prefix = "redis.cache")
@Component("sampleRedisConfig")
@RefreshScope
public class SampleRedisConfig implements InitializingBean {
  private static final Logger logger = LoggerFactory.getLogger(SampleRedisConfig.class);
  private int expireSeconds;
  private String clusterNodes;
  private int commandTimeout;
  private Map<String, String> someMap = Maps.newLinkedHashMap();
  private List<String> someList = Lists.newLinkedList();
  @Override
  public void afterPropertiesSet() throws Exception {
    logger.info(
        "SampleRedisConfig initialized - expireSeconds: {}, clusterNodes: {}, commandTimeout: {}, someMap: {}, someList: {}",
        expireSeconds, clusterNodes, commandTimeout, someMap, someList);
  }
  public void setExpireSeconds(int expireSeconds) {
    this.expireSeconds = expireSeconds;
  }
  public void setClusterNodes(String clusterNodes) {
    this.clusterNodes = clusterNodes;
  }
  public void setCommandTimeout(int commandTimeout) {
    this.commandTimeout = commandTimeout;
  }
  public Map<String, String> getSomeMap() {
    return someMap;
  }
  public List<String> getSomeList() {
    return someList;
  }
  @Override
  public String toString() {
    return String.format(
        "[SampleRedisConfig] expireSeconds: %d, clusterNodes: %s, commandTimeout: %d, someMap: %s, someList: %s",
        expireSeconds, clusterNodes, commandTimeout, someMap, someList);
  }
}

使用了RefreshScope進行刷新配置(重新create bean),但是不夠高效,最理想的事一個值發(fā)生變化只要重新把對應(yīng)的屬性set即可。

那么我們下面嘗試下,需要解決問題:

  • 確定@ApolloConfigChangeListener.value能不能填*表示匹配所有namespace。
  • 根據(jù)ConfigChangeEvent找到配置類及對應(yīng)的成員進行set。

解決@ApolloConfigChangeListener監(jiān)聽所有namespace

@ApolloConfigChangeListener(value = "*")
public void onChange(ConfigChangeEvent changeEvent) {
    log.info("onChange changeEvent:{}", changeEvent);
}

發(fā)現(xiàn)并不行。應(yīng)該可以編程式添加listener

編程式添加listener

找到官方文檔

Config config = ConfigService.getAppConfig();
config.addChangeListener(new ConfigChangeListener() {
  @Override
  public void onChange(ConfigChangeEvent changeEvent) {
    for (String key : changeEvent.changedKeys()) {
      ConfigChange change = changeEvent.getChange(key);
      System.out.println(String.format(
        "Found change - key: %s, oldValue: %s, newValue: %s, changeType: %s",
        change.getPropertyName(), change.getOldValue(),
        change.getNewValue(), change.getChangeType()));
        }
    }
});

ConfigService.getAppConfig()默認監(jiān)聽applicationnamespace,我們需要只監(jiān)聽項目依賴的的namespace。

獲取項目依賴的的namespace

google了一下發(fā)現(xiàn):apollo配置中心之--spring boot如何加載apollo。 可以通過environment獲取key為ApolloPropertySources,我們嘗試下:

@PostConstruct
public void registerApolloConfigChangeListener() {
    //從env中拿到所有已從Apollo加載的propertySource,獲取監(jiān)聽的nameSpace
    CompositePropertySource apolloPropertySources = (CompositePropertySource) configurableEnvironment.getPropertySources().get("ApolloPropertySources");
    if (Objects.isNull(apolloPropertySources)) {
        return;
    }
    Collection<PropertySource<?>> propertySourceList = apolloPropertySources.getPropertySources();
    //注冊監(jiān)聽所有加載的nameSpace
    propertySourceList.forEach(propertySource -> {
        ConfigChangeListener configChangeListener = changeEvent -> {
            for (String changedKey : changeEvent.changedKeys()) {
                ConfigChange change = changeEvent.getChange(changedKey);
                System.out.println(String.format(
                        "Found change - key: %s, oldValue: %s, newValue: %s, changeType: %s",
                        change.getPropertyName(), change.getOldValue(),
                        change.getNewValue(), change.getChangeType()));
            }
        };
        Config config = ConfigService.getConfig(propertySource.getName());
        config.addChangeListener(configChangeListener);
    });
}

尋找根據(jù)ConfigChangeEvent找到配置類及對應(yīng)的成員進行set的方式

google了一下,沒找到,但是spring肯定有相關(guān)的實現(xiàn),比如讀取yml后對 @ConfigurationProperties屬性進行填充,通過這篇文章找到ConfigurationPropertiesBindingPostProcessor是核心處理類:

通過ConfigurationPropertiesBindingPostProcessor#postProcessBeforeInitialization進行賦值,下面我們來看看能不能直接使用它:

package com.onepiece.apollo;
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.ConfigService;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.Comparator;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@Slf4j
@Component
public class ApolloRefreshConfig implements BeanPostProcessor, Ordered {
    @Resource
    private ConfigurableEnvironment configurableEnvironment;
    private Map<String, String> configPrefixBeanNameMapping;
    @Resource
    private ConfigurationPropertiesBindingPostProcessor configurationPropertiesBindingPostProcessor;
    @Resource
    private ApplicationContext applicationContext;
    /**
     * 注冊configChangeListener監(jiān)聽指定的NameSpace,默認的業(yè)務(wù)配置都在與應(yīng)用名命名的nameSpace,當然了如果希望監(jiān)聽到更多的自己去拿到配置的nameSpace也可以的
     */
    @PostConstruct
    public void registerApolloConfigChangeListener() {
        //從env中拿到所有已從Apollo加載的propertySource,獲取監(jiān)聽的nameSpace
        CompositePropertySource apolloPropertySources = (CompositePropertySource) configurableEnvironment.getPropertySources().get("ApolloPropertySources");
        if (Objects.isNull(apolloPropertySources)) {
            return;
        }
        Collection<PropertySource<?>> propertySourceList = apolloPropertySources.getPropertySources();
        //注冊監(jiān)聽所有加載的nameSpace
        propertySourceList.forEach(propertySource -> {
            ConfigChangeListener configChangeListener = changeEvent -> {
                for (String changedKey : changeEvent.changedKeys()) {
                    log.info("apollo changed namespace:{} Key:{} value:{}", changeEvent.getNamespace(), changedKey, changeEvent.getChange(changedKey));
                    String beanName = getBeanName(changedKey);
                    configurationPropertiesBindingPostProcessor.postProcessBeforeInitialization(applicationContext.getBean(beanName), beanName);
                }
            };
            Config config = ConfigService.getConfig(propertySource.getName());
            config.addChangeListener(configChangeListener);
        });
    }
    /**
     * register beanName with ConfigurationProperties#prefix if
     * annotation @ConfigurationProperties and @RefreshScope is existed
     *
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        ConfigurationProperties propertiesAnno = bean.getClass().getAnnotation(ConfigurationProperties.class);
        if (propertiesAnno != null) {
            if (configPrefixBeanNameMapping == null) {
                configPrefixBeanNameMapping = Maps.newHashMap();
            }
            String prefix = propertiesAnno.prefix() != null ? propertiesAnno.prefix() : propertiesAnno.value() == null ? null : propertiesAnno.value();
            if (StringUtils.isNotBlank(prefix) && StringUtils.isNotBlank(beanName)) {
                this.configPrefixBeanNameMapping.put(prefix, beanName);
            }
        }
        return bean;
    }
    @Override
    public int getOrder() {
        return 0;
    }
    /**
     * 防止可能出現(xiàn)的匹配到短prefix的情況,例如 key = "a.ab.abc", prefixA = "a", prefixB = "a.ab.abc",匹配到prefixA返回的情況,這里需要得到最匹配
     *
     * @param key
     * @return beanName best match key
     */
    private String getBeanName(String key) {
        if (configPrefixBeanNameMapping != null) {
            Optional<Map.Entry<String, String>> bestMatchEntry = configPrefixBeanNameMapping.entrySet().stream()
                    .filter(entryt -> key.startsWith(entryt.getKey() + "."))
                    .max(Comparator.comparing(Map.Entry<String, String>::getKey));
            return bestMatchEntry.map(Map.Entry::getValue).orElse(null);
        }
        return null;
    }
}

以上就是apollo更改配置刷新@ConfigurationProperties配置類的詳細內(nèi)容,更多關(guān)于apollo刷新@ConfigurationProperties的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 利用Spring Boot創(chuàng)建docker image的完整步驟

    利用Spring Boot創(chuàng)建docker image的完整步驟

    這篇文章主要給大家介紹了關(guān)于如何利用Spring Boot創(chuàng)建docker image的完整步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • spring boot啟動時加載外部配置文件的方法

    spring boot啟動時加載外部配置文件的方法

    這篇文章主要給大家介紹了關(guān)于spring boot啟動時加載外部配置文件的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-02-02
  • spring注解 @Valid 的作用說明

    spring注解 @Valid 的作用說明

    這篇文章主要介紹了spring注解 @Valid 的作用說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Spring boot中Jackson的操作指南

    Spring boot中Jackson的操作指南

    這篇文章主要給大家介紹了關(guān)于Spring boot中Jackson操作的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • Java編程反射機制用法入門與實例總結(jié)

    Java編程反射機制用法入門與實例總結(jié)

    這篇文章主要介紹了Java編程反射機制用法,簡單說明了反射機制的概念、原理并結(jié)合實例形式總結(jié)分析了java反射機制的簡單使用方法與相關(guān)注意事項,需要的朋友可以參考下
    2017-12-12
  • java的main方法中調(diào)用spring的service方式

    java的main方法中調(diào)用spring的service方式

    這篇文章主要介紹了在java的main方法中調(diào)用spring的service方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • 通過實例解析spring環(huán)繞通知原理及用法

    通過實例解析spring環(huán)繞通知原理及用法

    這篇文章主要介紹了通過實例解析spring環(huán)繞通知原理及用法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-10-10
  • Java結(jié)束線程的三種方法及該如何選擇

    Java結(jié)束線程的三種方法及該如何選擇

    這篇文章主要介紹了Java結(jié)束線程的三種方法及該如何選擇,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下
    2021-03-03
  • IntelliJ IDEA 2020.3 重大特性(新功能一覽)

    IntelliJ IDEA 2020.3 重大特性(新功能一覽)

    這篇文章主要介紹了IntelliJ IDEA 2020.3 重大特性(新功能一覽),本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • 使用@RequestParam 綁定List參數(shù)

    使用@RequestParam 綁定List參數(shù)

    這篇文章主要介紹了使用@RequestParam 綁定List參數(shù)的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08

最新評論