配置动态刷新@RefreshScope引起的取值为null
配置动态刷新@RefreshScope引起的取值为null
在Spring Cloud Config 动态刷新demo编写中,分为三个步骤:
1)git端配置更改,代码提交
2)手动刷新配置: POST请求: http://localhost:3355/actuator/refresh
3)客户端访问配置:http://localhost:3355/testConfig
控制类代码如下:
1 @RestController
2 @RefreshScope
3 public class ConfigClientTestController {
4 @Value("${config.info}")
5 private String configInfo;
6
7 /**
8 * 读取配置文件内容
9 *
10 * @return
11 */
12 @GetMapping("testConfig")
13 private String configInfo() {
14 return configInfo;
15 }
16 }
这个时候发现问题,客户端根本读取不到配置。
分析:
1)@RefreshScope 注解是 Spring Cloud 中用于标记需要在配置发生变化时进行刷新的 bean 的注解。当一个 bean 被 @RefreshScope 注解标记时,Spring 在创建这个 bean 的代理对象时会注入一些额外的逻辑,以便在配置变化时刷新这个 bean 的属性值。
2)代理对象是 Spring Framework 在运行时动态创建的对象,它包装了真实的 bean 对象,并在需要时执行一些额外的操作,比如在配置变化时刷新属性值。在使用 @RefreshScope 注解时,Spring 创建了一个代理对象来管理被注解标记的 bean,并在需要时负责刷新这个 bean 的属性值。
3)当我们在调用方法时,实际上是调用了代理对象的方法,代理对象会负责处理实际的调用逻辑,包括在配置变化时刷新属性值。因此,通过方法调用可以获取到最新的属性值,但直接访问 bean 的字段可能会得到旧值或者 null,因为直接访问的是代理对象的字段,而不是真实的 bean 对象。
根据上面的分析,将代码再改动一下:
1 @RestController 2 @RefreshScope 3 public class ConfigClientTestController { 4 @Value("${config.info}") 5 private String configInfo; 6 7 public String getConfig() { 8 return configInfo; 9 } 10 11 /** 12 * 读取配置文件内容 13 * 14 * @return 15 */ 16 @GetMapping("testConfig") 17 private String configInfo() { 18 return getConfig(); 19 } 20 }
这样就可以正常读取值了。
@RefreshScope 会使注入的值放到代理类中,而当前bean的属性字段是没有值的,直接读取bean的field会为null,只有通过方法(不一定是get方法)才会触发去代理类中取值
看到网上很多文章提到在@Controller中直接@Value获取不到值,解决方法是定义另外一个配置类,再取值就可以了。
配置类:
1 @Component 2 @RefreshScope 3 public class ConfigData { 4 @Value("${config.info}") 5 private String configInfo; 6 7 public String getConfigInfo() { 8 return configInfo; 9 } 10 }
控制类:
1 @RestController 2 @RequiredArgsConstructor(onConstructor_ = {@Autowired}) 3 public class ConfigClientController { 4 5 private final ConfigData configData; 6 7 /** 8 * 读取配置文件内容 9 * 10 * @return 11 */ 12 @GetMapping("getConfigInfo") 13 private String configInfo() { 14 return configData.getConfigInfo(); 15 } 16 }
这样也能正常读取到手动刷新后的配置值。不过,归根结底,出现读取不到最新值的原因其实跟取值方式有关,都是代理惹的祸。
取值方式 | 无@RefreshScope | 有@RefreshScope |
方式1(field取值) | 有值 | null |
方式2(方法取值) | 有值 | 有值 |
参考链接: https://www.jianshu.com/p/a535f8250cb2