gpt4 book ai didi

java - 在 ConfigurationProperties 更改后,使用 Spring @RefreshScope、@Conditional 注解替换运行时的 bean 注入(inject)

转载 作者:太空宇宙 更新时间:2023-11-04 10:13:38 24 4
gpt4 key购买 nike

我正在运行一个 PoC,以在 ConfigurationProperties 更改后在运行时替换 Bean 注入(inject)。这是基于spring boot动态配置属性支持以及总结的here作者:Pivotal 的 Dave Syer。

在我的应用程序中,我有一个由两个不同的具体类实现的简单接口(interface):

@Component
@RefreshScope
@ConditionalOnExpression(value = "'${config.dynamic.context.country}' == 'it'")
public class HelloIT implements HelloService {
@Override
public String sayHello() {
return "Ciao dall'italia";
}
}

@Component
@RefreshScope
@ConditionalOnExpression(value = "'${config.dynamic.context.country}' == 'us'")
public class HelloUS implements HelloService {
@Override
public String sayHello() {
return "Hi from US";
}

}

Spring Cloud配置服务器提供的application.yaml是:

config:
name: Default App
dynamic:
context:
country: us

以及相关的ConfigurationProperties类:

@Configuration
@ConfigurationProperties (prefix = "config.dynamic")
public class ContextHolder {

private Map<String, String> context;
Map<String, String> getContext() {
return context;
}

public void setContext(Map<String, String> context) {
this.context = context;
}

我的客户端应用程序入口点是:

@SpringBootApplication
@RestController
@RefreshScope
public class App1Application {

@Autowired
private HelloService helloService;

@RequestMapping("/hello")
public String hello() {
return helloService.sayHello();
}

第一次浏览http://locahost:8080/hello端点时,它返回“Hi from US”

之后,我在 Spring 配置服务器的 application.yaml 中的 country: it 中更改 country: us,然后点击 actuator/refresh 端点(在客户端应用程序上)。

我第二次浏览http://locahost:8080/hello时,它仍然返回“Hi from US”,而不是我所期望的“ciao dall'italia”。

使用 @RefreshScope 时,Spring Boot 2 支持此用例吗?我特别指的是将它与 @Conditional 注释一起使用的事实。

最佳答案

这个实现对我有用:

@Component
@RefreshScope
public class HelloDelegate implements HelloService {

@Delegate // lombok delegate (for the sake of brevity)
private final HelloService delegate;

public HelloDelegate(
// just inject value from Spring configuration
@Value("${country}") String country
) {
HelloService impl = null;
switch (country) {
case "it":
this.delegate = new HelloIT();
break;
default:
this.delegate = new HelloUS();
break;
}
}

}

它的工作方式如下:

  1. 当第一次调用服务方法时,Spring 创建 bean HelloDelegate ,配置此时生效; bean 被放入刷新范围缓存
  2. 因为 @RefreshScope 每当配置发生更改(country 属性,特别是在这种情况下)时,HelloDelegate bean 就会从刷新范围缓存中清除
  3. 当下一次调用时,Spring 必须再次创建 bean,因为缓存中不存在该 bean,因此使用新的 country 属性重复步骤 1

据我观察此实现的行为,如果配置未更改,Spring 将尝试避免重新创建 RefreshScope bean。

<小时/>

当发现这个问题时,我正在寻找更通用的解决方案来进行这种“运行时”实现替换。这种实现有一个显着的缺点:如果委托(delegate) bean 具有复杂的非同质配置(例如每个 bean 都有它自己的属性),那么代码就会变得很糟糕,因此不安全。

我使用这种方法来为工件提供额外的可测试性。这样 QA 就能够在 stub 集成和实际集成之间切换,而无需付出很大的努力。我强烈建议避免将这种方法用于业务功能。

关于java - 在 ConfigurationProperties 更改后,使用 Spring @RefreshScope、@Conditional 注解替换运行时的 bean 注入(inject),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52008261/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com