序言
Spring Cloud Bus將輕量級消息代理程序鏈接到分佈式系統的節點。然後可以將其用於廣播狀態更改(例如配置更改)或其他管理指令。當前唯一的實現是使用AMQP代理作爲傳輸,但是其他傳輸的路線圖上仍具有相同的基本功能集(還有一些取決於傳輸)。
此文章僅限入門 SpringCloud版本爲 Greenwich
就是說在使用了一些分佈式配置中心後(這裏以Spring Cloud Config爲例),這配置的刷新,一般我們都會重啓,但是我們使用了Spring Cloud Bus後啊,就可以做到這些配置的熱更新。
窺探
假設我們現在已經有一個項目使用了Spring Cloud Config 並且使用git 作爲配置文件的管理處啊。那麼我們可以在項目的依賴中加入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
並且這個項目yml加入
management:
endpoint:
health:
show-details: always
endpoints:
web:
exposure:
include: '*'
這裏啊我方便測試 我設置了 include: '*'
按道理可以,只引入-refresh
就行了。
然後這裏我們controller 里加入一個註解 @RefreshScope
@RestController
@RefreshScope
public class OrderController {
@Value("${fulinlin.name}")
String fulinlin;
@GetMapping("/getConfig")
public String getConfig() {
return fulinlin;
}
}
然後呢我們在git中 更新這個 fulinlin.name
這個屬性後,我們用命令調用一下/actuator/refresh
接口
curl -X POST http://localhost:7001/actuator/refresh
然後呢在控制檯中會打印一串日誌,這個串日誌呢就是,在從配置中心啊重新獲取配置。然後我們在訪問
http://localhost:7001/getConfig
可以發現這個配置啊已經刷新了。
使用
如果我們這個項目做了個集羣,難道我們要一個一個的去調用這個接口,做刷新嗎?有沒有一種簡單的方式呢?對就是bus。大概是這樣的,我們引用這個bus啊 結合mq官方有 rabbitmq kafka的實現,
然後每個引用bus的服務 都連接這個mq,啓動的時候給mq中創建一個隊列,然後這些隊列都會有同一個訂閱者
然後在我們的服務中專門有一個監聽,來監聽這個創建隊列,然後只要有一個服務提交了刷新請求,這些服務呢都會受到刷新的請求,這樣所有服務都刷新了。
在依賴中加入
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
這裏就使用rabbitmq了 kafka 其實使用起來跟這個沒啥區別的。
然後呢controller保持不變
@RestController
@RefreshScope
public class OrderController {
@Value("${fulinlin.name}")
String fulinlin;
@GetMapping("/getConfig")
public String getConfig() {
return fulinlin;
}
}
這裏可以使用 -Dserver.port
多起幾臺服務方便測試。啓動後我們在rabbimq的後臺查看一下是否有隊列進行創建
可以看到有一個springCloudBus
的一個交換器 是一個topic的類型,這裏你可以理解爲是一個發佈訂閱模式。
我們在git上事先先修改下 fulinlin.name
這個屬性。
然後在命令中發送
curl -X POST http://localhost:7001/actuator/bus-refresh
注意啊這裏是 bus-refresh
然後呢你看控制檯,打印了一串有關重新拉取的日誌。
然後你在刷新下請求看下,是不是這個fulinlin.name
這個屬性 已經更新了。
注意
本地配置中心
如果是使用的是本地配置中心。那麼你的配置中心需要重啓一下,切記啊,因爲本地配置中心在啓動的時候讀取的文件是不會因爲修改而重新讀取的!!!
刷新範圍
我們希望可以刷新微服務中某個具體實例的配置
Spring Cloud Bus對這種場景也有很好的支持:/actuator/bus-refresh
接口還提供了destination
參數,用來定位具體要刷新的應用程序。比如,我們可以請求/actuator/bus-refresh?destination=customers:9000
,此時總線上的各應用實例會根據destination
屬性的值來判斷是否爲自己的實例名,若符合才進行配置刷新,若不符合就忽略該消息。
destination
參數除了可以定位具體的實例之外,還可以用來定位具體的服務。定位服務的原理是通過使用Spring
的PathMatecher
(路徑匹配)來實現,比如:/actuator/bus-refresh?destination=customers:**
(以冒號的路徑分隔符:)來確定一個實例是否處理該消息,該配置的請求會觸發customers
服務的所有實例進行刷新。
優化
這裏是使用任意的一個服務端口來刷新配置了,其實你把這個工作交給配置中心也是沒問題的。在配置中心中加入
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
請求配置中心的 /actuator/bus-refresh
就可以做到配置的刷新了。
這裏始終要調取url,我們可以把這一步交個哦webhook
來做啊
但是webhook
不管哪個平臺都會帶一點參數,所以我們在配置中心自己定義下。
@SpringBootApplication
@EnableDiscoveryClient
@EnableConfigServer
@RestController
public class ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class, args);
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/bus-refresh")
public String busRefresh() {
HttpHeaders httpHeaders=new HttpHeaders();
httpHeaders.add("content-type","application/json;charset=UTF-8");
return restTemplate.postForObject("http://localhost:8888/actuator/bus-refresh", httpHeaders, String.class);
}
}
然後在對應代碼平臺的webhook
中配置一下你自定義的 url ,這樣就實現了你提交一次就動態更新啦。
此文章僅限入門,切記啊不會用找不到多去官網看文檔!