配置動態重新整理@RefreshScope引起的取值為null

欢乐豆123發表於2024-03-23

配置動態重新整理@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

相關文章