經過總線機制實現自動刷新客戶端配置(Consul,Spring Cloud Config,Spring Cloud Bus)

經過總線機制實現自動刷新客戶端配置

方案示意圖

Alt text

利用Git服務的webhook通知功能,在每次更新配置以後,Git服務器會用POST方式調用配置中心的/actuator/bus-refresh接口,配置中心的總線服務會將此事件廣播給加入總線的全部客戶端,客戶端收到事件後會重新讀取配置中心的內容。java

增長POM依賴

配置中心的服務端(spring-cloud-config-server)和客戶端(spring-cloud-config-client)都加入Spring Cloud Bus引用包:git

<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。github

修改配置信息

配置中心的服務端(spring-cloud-config-server)和客戶端(spring-cloud-config-client)都須要修改配置文件的內容:
spring-cloud-config-server項目的application.properties增長:web

# 開啓消息跟蹤
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

# 開啓消息跟蹤
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):docker

spring.cloud.config.fail-fast=true

配置Git的Webhook

Alt text
Alt text
Alt text

192.168.0.21:9004/actuator/bus-refresh是我一個配置中心的地址,若是有多個配置中心能夠寫多個webhook,在頁面上測試中若是返回204就說明成功了。shell

將Webhook的POST請求中的body清空

Git在進行webhood post請求的同時默認會在body加上這麼一串載荷(payload),Spring Boot 沒法並行化,因此在配置中心服務端(spring-cloud-config-server)新建下面兩個類:
此代碼參考了:spring_cloud config 配置中心及利用Github實現自動化熱加載配置bootstrap

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:
Alt text
Alt text
咱們更新Git參考將配置內容改成Test-9:
Alt text
Alt text
查看配置中心127.0.0.1:9004/ConfigDepot/Test,內容已經改成Test-9,再刷新客戶端程序127.0.0.1:9006/ConfigTest,這時配置內容已經成功改爲了Test-9,總線事件通知客戶端刷新配置成功。
Alt text
Alt text
從配置中心服務端和客戶端的日誌也可看出刷新配置信息的過程:
Alt text
Alt textapp

源碼

Github倉庫:https://github.com/sunweisheng/spring-cloud-example

相關文章
相關標籤/搜索