通過總線機制實現自動刷新客戶端配置
方案示意圖
利用Git服務的webhook通知功能,在每次更新配置之后,Git服務器會用POST方式調用配置中心的/actuator/bus-refresh接口,配置中心的總線服務會將此事件廣播給加入總線的所有客戶端,客戶端收到事件后會從新讀取配置中心的內容。
增加POM依賴
配置中心的服務端(spring-cloud-config-server)和客戶端(spring-cloud-config-client)都加入Spring Cloud Bus引用包:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
啟動Rabbitmq
docker pull rabbitmq:3-management
docker run -d --hostname my-rabbit --name rabbit -p 5672:5672 -p 15672:15672 rabbitmq:3-management
可以訪問127.0.0.1:15672/登錄rabbitmq管理監控后台,用戶名密碼都是guest/guest。
修改配置信息
配置中心的服務端(spring-cloud-config-server)和客戶端(spring-cloud-config-client)都需要修改配置文件的內容:
spring-cloud-config-server項目的application.properties增加:
# 開啟消息跟蹤
spring.cloud.bus.trace.enabled=true
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#顯示的暴露接入點
management.endpoints.web.exposure.include=*
spring-cloud-config-client項目的application.properties增加:
# 開啟消息跟蹤
spring.cloud.bus.trace.enabled=true
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#顯示的暴露接入點
management.endpoints.web.exposure.include=*
spring-cloud-config-client項目的bootstrap.properties增加(否則會報錯:A component required a bean named 'configServerRetryInterceptor' that could):
spring.cloud.config.fail-fast=true
配置Git的Webhook
192.168.0.21:9004/actuator/bus-refresh是我一個配置中心的地址,如果有多個配置中心可以寫多個webhook,在頁面上測試中如果返回204就說明成功了。
將Webhook的POST請求中的body清空
Git在進行webhood post請求的同時默認會在body加上這么一串載荷(payload),Spring Boot 無法並行化,所以在配置中心服務端(spring-cloud-config-server)新建下面兩個類:
此代碼參考了:spring_cloud config 配置中心及利用Github實現自動化熱加載配置
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
//清空請求中的Body
public class EmptyRequestWrapper extends HttpServletRequestWrapper{
public EmptyRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public ServletInputStream getInputStream() throws IOException {
byte[] bytes = new byte[0];
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return byteArrayInputStream.read() == -1 ? true:false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
};
}
}
import org.springframework.core.annotation.Order;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@WebFilter(filterName = "bodyFilter", urlPatterns = "/*")
@Order(1)
//Git在進行webhood post請求的同時默認會在body加上這么一串載荷(payload),Spring Boot 無法並行化。
public class BusRefreshFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest)servletRequest;
String url = new String(httpServletRequest.getRequestURI());
//只過濾/actuator/bus-refresh請求
if (!url.endsWith("/bus-refresh")) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
//使用HttpServletRequest包裝原始請求達到修改post請求中body內容的目的
EmptyRequestWrapper requestWrapper = new EmptyRequestWrapper(httpServletRequest);
filterChain.doFilter(requestWrapper, servletResponse);
}
@Override
public void destroy() {
}
}
最后在啟動類上添加@ServletComponentScan注解
@SpringBootApplication
//啟動配置中心
@EnableConfigServer
//啟動服務發現
@EnableDiscoveryClient
@ServletComponentScan
public class SpringCloudConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudConfigServerApplication.class, args);
}
}
測試自動刷新自動
訪問客戶端程序127.0.0.1:9006/ConfigTest,得到當前結果Test-8,訪問配置中心也是Test-8:
我們更新Git參考將配置內容改為Test-9:
查看配置中心127.0.0.1:9004/ConfigDepot/Test,內容已經改為Test-9,再刷新客戶端程序127.0.0.1:9006/ConfigTest,這時配置內容已經成功改成了Test-9,總線事件通知客戶端刷新配置成功。
從配置中心服務端和客戶端的日志也可看出刷新配置信息的過程:
源碼
Github倉庫:https://github.com/sunweisheng/spring-cloud-example