咱們在上一篇講到,Spring Boot程序只在啓動的時候加載配置文件信息,這樣在GIT倉庫配置修改以後,雖然配置中心服務器可以讀取最新的提交信息,可是配置中心客戶端卻不會從新讀取,以致於不能及時的讀取更新後的配置信息。這個時候就須要一種通知刷新機制來支持了。html
refresh機制是Spring Cloud Config提供的一種刷新機制,它容許客戶端經過POST方法觸發各自的/refresh,只要依賴spring-boot-starter-actuator包就擁有了/refresh的功能,下面咱們爲咱們的客戶端加上刷新功能,以支持更新配置的讀取。java
修改 spring-cloud-conifg-client,添加監控依賴,監控依賴包裏攜帶了 /refresh 的功能。git
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
在使用配置屬性的類型加上 @RefreshScope 註解,這樣在客戶端執行 /refresh 的時候就會刷新此類下面的配置屬性了。web
package com.louis.spring.cloud.config.client.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RefreshScope @RestController class HelloController { @Value("${spring.config.hello}") private String hello; @RequestMapping("/hello") public String from() { return this.hello; } }
修改配置文件添加如下內容,開放refresh的相關接口。spring
bootstrap.ymldocker
management: endpoints: web: exposure: include: "*"
這樣,之後以post請求的方式訪問 http://localhost:8552/actuator/refresh 時,就會更新修改後的配置文件了。bootstrap
特別注意:跨域
這裏存在着版本大坑,1.x跟2.x的配置不太同樣,咱們用的是2.0+版本,務必注意。安全
1.安全配置變動服務器
新版本
management.endpoints.web.exposure.include="*"
老版本
management.security.enabled=false
2.訪問地址變動
新版本
http://localhost:8552/actuator/refresh
老版本
http://localhost:8552/refresh
這裏仍是解釋一下上面這個配置起到了什麼具體做用,其實actuator是一個健康檢查包,它提供了一些健康檢查數據接口,refresh功能也是其中的一個接口,可是爲了安全起見,它默認只開放了health和info接口(啓動信息會包含以下圖所示信息),而上面的配置就是設置要開放哪些接口, 咱們設置成 「*」,是開放全部接口。你也能夠指定開發幾個,好比: health,info,refresh,而這裏由於咱們須要用的refresh功能,因此須要把refresh接口開放出來。
設置成 「*」 後,啓動信息會包含如下信息,而這個叫refresh的post方法,就是咱們須要的,上面說的接口地址變動從這裏也能夠看得出來。
訪問 http://localhost:8552/hello,返回結果以下。
修改倉庫配置內容,把數字2改爲5,以下圖所示。
再次訪問 http://localhost:8552/hello,如咱們所料,結果並無更新,由於咱們尚未調refresh方法。
經過工具或自寫代碼發送post請求 http://localhost:8552/actuator/refresh,刷新配置。
這裏經過在線測試網站發送,地址:https://getman.cn/Mo2FX 。
注意:先讓你的Chrome支持跨域。設置方法:在快捷方式的target後加上 --disable-web-security --user-data-dir,重啓便可。
刷新以後,再次訪問 http://localhost:8552/hello,返回結果以下。
查看返回結果,刷新以後已經能夠獲取最新提交的配置內容,可是每次都須要手動刷新客戶端仍是很麻煩,若是客戶端數量一多就簡直難以忍受了,有沒有什麼比較好的辦法來解決這個問題呢,那是固然的,答案就是:Spring Cloud Bus。
Spring Cloud Bus,被你們稱爲消息總線,它經過輕量級的消息代理來鏈接各個分佈的節點,能夠利用像消息隊列的廣播機制在分佈式系統中進行消息傳播,經過消息總線能夠實現不少業務功能,其中對於配置中心客戶端刷新,就是一個很是典型的使用場景。
下面這張圖能夠很好的解釋消息總線的做用流程(圖片描述來源:純潔的微笑:配置中心博文)。
Spring Cloud Bus 進行配置更新步驟以下:
一、提交代碼觸發post請求給/actuator/bus-refresh
二、server端接收到請求併發送給Spring Cloud Bus
三、Spring Cloud bus接到消息並通知給其它客戶端
四、其它客戶端接收到通知,請求Server端獲取最新配置
五、所有客戶端均獲取到最新的配置
由於咱們須要用到消息隊列,咱們這裏選擇RabbitMQ,使用Docker進行安裝。
執行如下命令,拉取鏡像。
docker pull rabbitmq:management
完成以後執行如下命令查看下載鏡像。
docker images
執行如下命令,建立docker容器。
docker run -d --name rabbitmq -p 5671:5671 -p 5672:5672 -p 4369:4369 -p 25672:25672 -p 15671:15671 -p 15672:15672 rabbitmq:management
啓動成功以後,能夠執行如下命令查看啓動容器。
docker ps
容器啓動以後就能夠訪問web管理界面了,訪問 http://宿主機IP:15672。
系統提供了默認帳號。 用戶名:guest 密碼: guest
管理界面
打開客戶端 spring-cloud-conifg-client,添加相關依賴。
pom.xml
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency>
修改配置,添加RebbitMq的相關配置,這樣客戶端代碼就改造完成了。
bootstrap.yml
spring: application: name: spring-cloud-config-client cloud: consul: host: localhost port: 8500 discovery: serviceName: ${spring.application.name} # 註冊到consul的服務名稱 config: discovery: enabled: true serviceId: spring-cloud-config-server # 配置中心服務名稱 name: spring-config # 對應{application}部分 profile: dev # 對應{profile}部分 label: master # 對應git的分支,若是配置中心使用的是本地存儲,則該參數無用 rabbitmq: host: localhost port: 5672 username: guest password: guest management: endpoints: web: exposure: include: "*"
修改 spring-cloud-conifg-server,添加相關依賴。
pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency>
修改配置,添加RebbitMq的和接口開放相關配置,這樣服務端代碼也改造完成了。
application.yml
server: port: 8551 spring: application: name: spring-cloud-config-server cloud: consul: host: localhost port: 8500 discovery: serviceName: ${spring.application.name} # 註冊到consul的服務名稱 config: server: git: uri: https://gitee.com/liuge1988/spring-cloud-demo/ # 配置git倉庫的地址 search-paths: config-repository # git倉庫地址下的相對地址,能夠配置多個,用,分割。 username: username # git倉庫的帳號 password: password # git倉庫的密碼 rabbitmq: host: localhost port: 5672 username: guest password: guest management: endpoints: web: exposure: include: "*"
1.啓動服務端,成功集成消息總線後,啓動信息中能夠看到以下圖中的信息。
2.啓動客戶端,發現竟然報錯了,網上也找不到相關資料,也沒見其餘人提過相關問題。猜想是網上教程可能是使用Euraka,而這裏用的時Consul,瞎鼓搗了很久,反正是不想換回Euraka,2.0中止開發消息出來之後,未來還不定什麼狀況,只能硬着頭皮解決了。
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'configServerRetryInterceptor' available at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:685) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1210) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE] at org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor.getDelegate(AnnotationAwareRetryOperationsInterceptor.java:180) ~[spring-retry-1.2.2.RELEASE.jar:na] at org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor.invoke(AnnotationAwareRetryOperationsInterceptor.java:151) ~[spring-retry-1.2.2.RELEASE.jar:na] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.8.RELEASE.jar:5.0.8.RELEASE] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.0.8.RELEASE.jar:5.0.8.RELEASE] at org.springframework.cloud.config.client.ConfigServerInstanceProvider$$EnhancerBySpringCGLIB$$dd44720b.getConfigServerInstances(<generated>) ~[spring-cloud-config-client-2.0.0.RELEASE.jar:2.0.0.RELEASE] at org.springframework.cloud.config.client.DiscoveryClientConfigServiceBootstrapConfiguration.refresh(DiscoveryClientConfigServiceBootstrapConfiguration.java:84) [spring-cloud-config-client-2.0.0.RELEASE.jar:2.0.0.RELEASE] at org.springframework.cloud.config.client.DiscoveryClientConfigServiceBootstrapConfiguration.startup(DiscoveryClientConfigServiceBootstrapConfiguration.java:69) [spring-cloud-config-client-2.0.0.RELEASE.jar:2.0.0.RELEASE] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_131] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131]
而後就跟蹤代碼,發現是在下圖中的位置找不到相應的Bean,那麼答案就比較明顯了,要麼是程序有BUG,不過可能性不大,那應該是就是缺包了,在缺失的包裏有這個Bean。可是這個Bean是在哪一個包?排查了半天也沒找到,網上也沒有想過資料,對比了一下網上消息總線的配置,依賴也沒有少加什麼。
沒有辦法,最後只能本身上手了,不就是在刷新的時候缺乏一個攔截器嗎,本身給他弄一個試試唄。
使用就加了一個配置類,並在resources下新建了META-INF目錄和一個spring。factories文件。
RetryConfiguration.java
package com.louis.spring.cloud.config.client; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.retry.interceptor.RetryInterceptorBuilder; import org.springframework.retry.interceptor.RetryOperationsInterceptor; public class RetryConfiguration { @Bean @ConditionalOnMissingBean(name = "configServerRetryInterceptor") public RetryOperationsInterceptor configServerRetryInterceptor() { return RetryInterceptorBuilder.stateless().backOffOptions(1000, 1.2, 5000).maxAttempts(10).build(); } }
spring.factories
org.springframework.cloud.bootstrap.BootstrapConfiguration=com.louis.spring.cloud.config.client.RetryConfiguration
在這裏指定新建的攔截器,這樣系統初始化時會加載這個Bean。
而後重啓啓動,果真沒有報錯了,仍是先別高興,看看能不能用先。
4.先訪問一下 http://localhost:8552/hello,效果以下圖所示。
5.修改倉庫配置文件,把數字5改爲15,修改完成提交。
再次訪問發現仍是舊信息。
6.再用工具發送post請求 http://localhost:8551/actuator/bus-refresh 。
注意此次是向註冊中心服務端發送請求,發送成功以後服務端會經過消息總線通知全部的客戶端進行刷新。
另外開啓消息總線後的請求地址是 /actuator/bus-refresh,再也不是refresh了。
7.給服務端發送刷新請求以後,再次訪問 http://localhost:8552/hello,結果以下。
咱們愉快的發現客戶端已經可以經過消息總線獲取最新配置了,真是可喜可賀。
碼雲:https://gitee.com/liuge1988/spring-cloud-demo.git
做者:朝雨憶輕塵
出處:https://www.cnblogs.com/xifengxiaoma/ 版權全部,歡迎轉載,轉載請註明原文做者及出處。