Spring云配置刷新后如何执行自定义逻辑?

Posted

技术标签:

【中文标题】Spring云配置刷新后如何执行自定义逻辑?【英文标题】:How can I execute custom logic after Spring cloud configuration refresh? 【发布时间】:2018-05-23 00:01:09 【问题描述】:

我已将我的应用程序设置为使用 Spring 云配置来提供配置并启用监视器,以便配置服务器将更改事件发布到我的应用程序。配置已正确更新,但我希望在配置更改时收到通知,以便我可以根据新配置执行一些自定义逻辑。

我有这个配置对象

@Configuration
@RefreshScope
@ConfigurationProperties(prefix = "my.prefix")
public class MyConfig 
    private Map<String, MyObject> configs;
    private String someValue;

    public Map<String, MyObject> getConfigs()...
    public void setConfigs()...

    public String getSomeValue()...
    public void setSomeValue()...

...
public class MyObject 
   private String field1;

   public String getField1() ...
   public void setField1() ...

这在我的配置服务器 application.yml 中

my:
  prefix:
    configs:
      TEST:
        field1: "testValue"
    someValue: "test"

现在,当我在配置中更改 someValue 并且配置服务器发布刷新时,它会调用 setSomeValue() 并将值更新为新值。我可以将我的自定义逻辑添加到 setSomeValue() 并且它会正常工作。但是,在从配置中更新或添加/删除条目时,它似乎没有调用 setConfigs() 或 setField1()。

我尝试为 EnviornmentChangeEvents、RefreshEvents 或 RefreshScopeRefreshedEvents 注册一个侦听器,但这些侦听器要么在 Spring 更新值之前触发,要么根本不触发。我还尝试向 @PreDestroy 和 @PostConstruct 方法添加逻辑,但只有 PreDestroy 最终被调用,并且在配置更新之前被调用。我也尝试实现 InitializingBean 并将我的逻辑放入 afterPropertiesSet() 但它也从未被调用过。

如何在此配置更新时收到通知?

【问题讨论】:

【参考方案1】:

使用 RefreshScopeRefreshedEvent 侦听器,您可以在配置更新时收到通知。

以下示例适用于我:

配置:

@Configuration
public class Config 
    @Bean
    @RefreshScope
    public A aBean() 
        return new A();
    

    @Bean
    public RefreshScopeRefreshedListener remoteApplicationEventListener(A aBean) 
        return new RefreshScopeRefreshedListener(aBean);
    


而听众:

public class RefreshScopeRefreshedListener implements ApplicationListener<RefreshScopeRefreshedEvent> 
    private A aBean;

    public RefreshScopeRefreshedListener(A abean) 
        this.aBean = abean;
    

    @Override
    public void onApplicationEvent(RefreshScopeRefreshedEvent event) 
        System.out.println(aBean.getValue());

    


它总是打印配置的新值。

如果你已经尝试过这个监听器,你确定它已经注册好了吗? bean 是否已正确创建?

【讨论】:

这肯定会起作用,但是即使对于其他属性更改它也总是会触发该方法,我认为 RefreshScopeRefreshedEvent 中缺少的是 EnvironmentChangeEvent 可以提供的 getKeys() 方法,但是 EnvironmentChangeEvent 不保证bean @Refreshscope 已更新【参考方案2】:

我所做的是获取EnvironmentChangeEvent监听器的钩子,然后从Environment本身而不是@Autowired Bean bean获取更新的属性

@Autowired
private Environment env;

@EventListener(EnvironmentChangeEvent.class)
public void onApplicationEvent(EnvironmentChangeEvent environmentChangeEvent) 
    log.info("Received an environment changed event for keys ", environmentChangeEvent.getKeys());
    if(environmentChangeEvent.getKeys().contains("key.i.wanted.to.recalculate")) 
        String newValue = env.getProperty("key.i.wanted.to.recalculate");
        System.out.println("New Value: " + newValue);
    

【讨论】:

【参考方案3】:

或者,您可以使用@ConfigurationProperties 添加@PostConstruct,以便您可以编写自定义逻辑

@ConfigurationProperties(prefix = "dummy.just.to.trigger.actuator.refresh")
Class AnyPropLoader 
@PostConstruct
private void customLogicMethod()
...


【讨论】:

以上是关于Spring云配置刷新后如何执行自定义逻辑?的主要内容,如果未能解决你的问题,请参考以下文章

如何让网页局部定时刷新?

spring boot整合 spring security之自定义退出

企业分布式微服务云SpringCloud SpringBoot mybatis (十九)Spring Boot 自定义配置文件

解析graphql查询后实现自定义逻辑

利用Spring的ApplicationEvent执行自定义方法

SpringBoot自定义校验注解