配置動態刷新@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