亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

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

發布時間:2023-04-07 17:47:04 來源:億速云 閱讀:265 作者:iii 欄目:開發技術

這篇文章主要介紹了apollo怎么更改配置刷新@ConfigurationProperties配置類的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇apollo怎么更改配置刷新@ConfigurationProperties配置類文章都會有所收獲,下面我們一起來看看吧。

    前言

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

    • 統一管理一組配置。

    • 配置變化的時需要觸發相關變動只涉及一個bean。

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

    可以大概看看:

    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配置變化監聽器,內部使用了cloud發布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),但是不夠高效,最理想的事一個值發生變化只要重新把對應的屬性set即可。

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

    • 確定@ApolloConfigChangeListener.value能不能填*表示匹配所有namespace。

    • 根據ConfigChangeEvent找到配置類及對應的成員進行set。

    解決@ApolloConfigChangeListener監聽所有namespace

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

    發現并不行。應該可以編程式添加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()默認監聽applicationnamespace,我們需要只監聽項目依賴的的namespace。

    獲取項目依賴的的namespace

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

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

    @PostConstruct
    public void registerApolloConfigChangeListener() {
        //從env中拿到所有已從Apollo加載的propertySource,獲取監聽的nameSpace
        CompositePropertySource apolloPropertySources = (CompositePropertySource) configurableEnvironment.getPropertySources().get("ApolloPropertySources");
        if (Objects.isNull(apolloPropertySources)) {
            return;
        }
        Collection<PropertySource<?>> propertySourceList = apolloPropertySources.getPropertySources();
        //注冊監聽所有加載的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);
        });
    }

    尋找根據ConfigChangeEvent找到配置類及對應的成員進行set的方式

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

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

    通過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監聽指定的NameSpace,默認的業務配置都在與應用名命名的nameSpace,當然了如果希望監聽到更多的自己去拿到配置的nameSpace也可以的
         */
        @PostConstruct
        public void registerApolloConfigChangeListener() {
            //從env中拿到所有已從Apollo加載的propertySource,獲取監聽的nameSpace
            CompositePropertySource apolloPropertySources = (CompositePropertySource) configurableEnvironment.getPropertySources().get("ApolloPropertySources");
            if (Objects.isNull(apolloPropertySources)) {
                return;
            }
            Collection<PropertySource<?>> propertySourceList = apolloPropertySources.getPropertySources();
            //注冊監聽所有加載的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;
        }
        /**
         * 防止可能出現的匹配到短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配置類”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“apollo怎么更改配置刷新@ConfigurationProperties配置類”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    锦屏县| 大丰市| 平泉县| 永登县| 南投县| 卢湾区| 来安县| 虎林市| 大同县| 乌兰察布市| 阜平县| 吕梁市| 聂拉木县| 彰武县| 霍山县| 磴口县| 江安县| 宝应县| 若尔盖县| 信阳市| 屏东市| 白城市| 平凉市| 阿荣旗| 克东县| 长沙市| 陆良县| 宜良县| 简阳市| 曲松县| 三亚市| 合水县| 会泽县| 宜州市| 清流县| 奉化市| 新闻| 祥云县| 安乡县| 利辛县| 哈尔滨市|