更多Spring文章,歡迎點擊 一灰灰Blog-Spring專題java
配置的刷新,從第一篇就提出了這個問題,可是一直都沒有說到,那麼配置加載完畢以後可否在主動刷新呢?git
若是對SpringCloud有了解的話,會直到有個配置中心的微服務,專門就是來作配置遠程拉取,固然也支持刷新了,這是否意味着能夠支持刷新呢,若是支持該怎麼作?github
<!-- more -->web
本篇將介紹並演示如何實現配置信息的刷新,但不會涉及到底層的實現原理,想要探究裏面的神奇,能夠網上google一下,或者期待後續的源碼分析篇spring
咱們這裏主要藉助這個類來實現配置刷新,至於從哪裏撈出來的這個東西,從Spring-Cloud-Config出發,看了下它怎麼玩的,而後依葫蘆畫瓢app
這個類全路徑爲 org.springframework.cloud.context.refresh.ContextRefresher
,所以你的SpringBoot項目須要作一點修改dom
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-context</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
接下來就簡單了,直接調用這個類的refresh()
方法就能夠了,just so easy~spring-boot
配置文件: application.yml微服務
biz: refresh: ${random.long} key: refresh-test rest: uuid: ${random.uuid} server: port: 8081
讀取配置的bean,演示了兩種獲取方式,分別以下源碼分析
@Data @Component @ConfigurationProperties(prefix = "biz") public class BizConfig { private String key; private Long refresh; }
開啓刷新的@Value
註解方式,注意下面的@RefreshScoe
註解,這個必須有,負責更新後的配置不會同步
@Data @RefreshScope @Component public class ValueConfig { @Value("${rest.uuid}") private String uuid; }
測試Controller
以下
@RestController public class DemoController { @Autowired private ContextRefresher contextRefresher; @Autowired private BizConfig bizConfig; @Autowired private ValueConfig valueConfig; @GetMapping(path = "/show") public String show() { JSONObject res = new JSONObject(); res.put("biz", JSONObject.toJSONString(bizConfig)); res.put("uuid", valueConfig.getUuid()); return res.toJSONString(); } @GetMapping(path = "/refresh") public String refresh() { new Thread(() -> contextRefresher.refresh()).start(); return show(); } }
啓動上面的應用,而後開啓愉快的測試,調用refresh接口,發現每次的返回都不同(由於配置文件使用了random隨機生成),可是訪問show接口時,每次返回的都是同樣的,也就是說refresh接口中確實實現了配置的刷新
說明
ConfigurationProperties
方式獲取註解時,自動支持刷新配置@Value
註解的方式,須要開啓@RefreshScope
註解(上面沒有演示不開啓這個註解的狀況, 建議有興趣的能夠本身嘗試一下)既然配置能刷新,那麼若是我但願獲取配置變動的事件,而後作一些其餘的事情,是否ok呢?
其實進入 ContextRefresher
的源碼,看下refresh接口,就很明確了
public synchronized Set<String> refresh() { Map<String, Object> before = extract( this.context.getEnvironment().getPropertySources()); addConfigFilesToEnvironment(); Set<String> keys = changes(before, extract(this.context.getEnvironment().getPropertySources())).keySet(); // 注意這一行,拋出了一個變動事件 this.context.publishEvent(new EnvironmentChangeEvent(context, keys)); this.scope.refreshAll(); return keys; }
從上面的源碼中,藉助spring的事件通知機制,很簡單就能夠知道該怎麼作了,來一個簡單的demo,這裏順帶測試下上面漏掉的不刷新的場景
@RestController public class DemoController { @Autowired private ContextRefresher contextRefresher; @Autowired private BizConfig bizConfig; @Autowired private ValueConfig valueConfig; @Value("${rest.uuid}") private String uuid; @GetMapping(path = "/show") public String show() { JSONObject res = new JSONObject(); res.put("biz", JSONObject.toJSONString(bizConfig)); res.put("uuid", valueConfig.getUuid()); res.put("no-refresh", uuid); return res.toJSONString(); } @GetMapping(path = "/refresh") public String refresh() { new Thread(() -> contextRefresher.refresh()).start(); return show(); } @EventListener public void envListener(EnvironmentChangeEvent event) { System.out.println("conf change: " + event); } }
直接將Listener寫在Controller類內部... 原則上不推薦上面的寫法
依然來個實測,主要注意下控制檯的輸出便可
一灰灰的我的博客,記錄全部學習和工做中的博文,歡迎你們前去逛逛
盡信書則不如,已上內容,純屬一家之言,因我的能力有限,不免有疏漏和錯誤之處,如發現bug或者有更好的建議,歡迎批評指正,不吝感激
一灰灰blog
知識星球