配置动态刷新@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 

posted @ 2024-03-23 21:49  欢乐豆123  阅读(172)  评论(0编辑  收藏  举报