map注入 ,使用 @ConfigurationProperties , 修改apollo配置后不会动态修改的问题

发布时间 2023-04-27 11:37:25作者: lshan

问题:

apollo动态刷新,应用在@value这种注入方式的属性没有问题,但是如果使用@ConfigurationProperties注解的bean,动态刷新就不好使了,会注入不到的。

Apollo动态刷新官网介绍

需要注意的是,@ConfigurationProperties如果需要在Apollo配置变化时自动更新注入的值

需要配合使用EnvironmentChangeEventRefreshScope

相关代码实现,可以参考apollo-use-cases项目中的ZuulPropertiesRefresher.java和apollo-demo项目中的SampleRedisConfig.java以及SpringBootApolloRefreshConfig.java

 

例如注入一个 map  对象: {"Sea":"v1","Sea1" :"v2"} ,希望动态修改

applocation.yml: 

#my.user.config
sea.xx.user_config[Sea]=v1 sea.xx.user_config[dmisy]
= {"name":"dmisy","secret":"d6f57e00f2","type":"a"} sea.xx.user_config[jerry] = {"name":"jerry","secret":"e73d18909cdaa","type":"b"}
@Service
@ConfigurationProperties(prefix = "sea.xx")
public class UserServiceImpl implements UserService {
    public  Map<String,String> user_config =new HashMap<String,String>() ;
    public  void setUser_config(Map<String, String> user_config) {
        this.user_config = user_config;
    }
  

现在如果想修改,或添加配置, 服务需要重启财生效

 

解决方案:

step1. 添加  @RefreshScope

    @Service
    @RefreshScope
    @ConfigurationProperties(prefix = "sea.xx")
    public class UserServiceImpl implements UserService {
        public  Map<String,String> user_config =new HashMap<String,String>() ;

step2: add   ApolloChangeListener  

/***************************
 *<pre>
 * @Author       : Sea
 * @Mail         : lshan523@16.com
 * @Date         : 2023/4/27 10:29
 * 用于解决 被@ConfigurationProperties修饰的类, 修改apollo配置后不会动态修改的问题
 * 使用方式:
 *  被@ConfigurationProperties修饰的类 需要加上:@Component  @RefreshScope  注解
 *</pre>
 ***************************/
@Slf4j
@Configuration
public class ApolloChangeListener  {
    @Autowired
    private RefreshScope refreshScope;
    /**
     * 使用说明
     *   @ApolloConfigChangeListener(value = {"application.yml","user"}, interestedKeyPrefixes = {"spring.","my.config"}):
     *   当在Apollo配置中心,修改application.yml或user.properties下的,前缀为spring.或my.config的属性时,触发刷新方法执行。
     * @param changeEvent
     */
    @ApolloConfigChangeListener(value = "application.yml", interestedKeyPrefixes = "sea.xx.")
    public void refresh(ConfigChangeEvent changeEvent) {
        log.info("Changes for namespace " + changeEvent.getNamespace());
        for(String key : changeEvent.changedKeys()) {
            ConfigChange change = changeEvent.getChange(key);
            log.info(String.format("Found change - key: %s, oldValue: %s, newValue: %s, changeType: %s", change.getPropertyName(), change.getOldValue(), change.getNewValue(), change.getChangeType()));
        }
        // 刷新的bean 所有 带@RefreshScope 的类
          refreshScope.refreshAll();
        // 刷新指定的bean
//        refreshScope.refresh("myConfigProperties");
    }
}

 

 

这样就可以动态修改这个map了

 

!!!  对于 mysql  redis mongo 等DB, 依然需要重启, 或者添加 重新建立连接的逻辑,财真的生效