J360-cloud SpringCloud系列一:分佈式配置服務器ConfigServer

j360開源博客之

----------------------------------------------------------java

J360-Cloud系列

spring-cloud快速入門工程之j360-cloud-all:(歡迎star、forkgit

https://github.com/xuminwlt/j360-cloud-allgithub


spring cloud系列博客web

J360-cloud SpringCloud系列二:服務發現Discovery Service
spring


SpringCloud構建在Springboot基礎上,如何使用SpringBoot請轉移到shell

j360-boot

spring-boot入門工程之j360-boot:(歡迎star、forkbootstrap

https://github.com/xuminwlt/j360-boot服務器

spring-boot官方地址app

http://projects.spring.io/spring-boot/
分佈式


分佈式配置

Spring Cloud分佈式配置服務由服務器端和客戶端共同組成,Server端提供配置信息的存儲管理,客戶端完成配置信息的調度,工程結構以下

套用一個圖來解釋該部分在springCloud分佈式系統中的結構


上面的圖片說明了四個微服務以及各個服務之間的依賴關係。 
configuration service 處於最頂端,黃色標識,並且被其餘微服務所依賴。 
discovery service 處於最低端,藍色標識,同時也被其餘服務所依賴。 


- bootstrap.yml

- application.yml

- 【注】建議採用bootstrap+application組合形式,通常bootstrap配置工程不可變參數,且在啓動時須要設定的內容,application配置可變參數

J360-cloud-configserver

一、POM依賴

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-starter-eureka</artifactId>
                </dependency>

二、註解

- configserver提供了HTTP,爲外部資源提供API配置的服務,只須要在Springboot程序中提供@EnableConfigServer註解便可。

    - @EnableConfigServer

    - 增長如下依賴 eureka(可選,做爲discover服務器必選)

三、配置文件

bootstrap.properties

spring.application.name=configserver

spring.cloud.config.uri=http://localhost:8888

application.properties

server.port=8888

spring.cloud.config.server.git.uri=https://github.com/xuminwlt/config-repo

四、spring-boot:run

http://localhost:8888/configserver/application.properties

J360-cloud-client

一、POM

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

二、配置

bootstrap.properties

spring.application.name=client
spring.cloud.config.uri=http://localhost:8888

application.properties

server.port=8080

apply.message=local message
user.username=xumin

三、spring-boot:run

四、http://localhost:8080/env 查看環境變量

五、http://localhost:8080/refresh  post方法,更新client中的配置  

【注】環境變量刷新 

    - post -> localhost:8080/refresh

    - 定時

    - 手動


環境變量倉庫

默認的環境變量庫使用git服務,也可使用文件系統的服務

一、git服務

https://github.com/xuminwlt/config-repo

二、文件服務

使用 spring.profiles.active=native

環境變量倉庫使用3個變量:

- {application} 在客戶端映射到"spring.application.name"

- {profile} 在客戶端映射到"spring.active.profiles",使用逗號分隔

- {label}這是一個服務器端功能標籤「版本」的一組配置文件


自動刷新

當環境變量參數經過git更新後,客戶端自動更新:

1:可使用 post /refresh來執行,客戶端調用更新功能,configServer pull git完成後,更新環境變量信息,客戶端獲取最新的環境變量,而且更新

2:定時器執行:每隔X時間段更新一次

3:根據須要執行:只須要將定時器調用的更新接口暴露成服務形式調用

多客戶端更新服務

1:經過Spring Cloud Bus更新

2:其餘廣播形式調用接口

調用接口:

/**
 * 手動刷新git更新方案,每20S執行一次,能夠修改爲手動執行,同/refresh
 * @link RefreshEndpoint
 * */
public void refresh() {
    Map<String, Object> before = extract(context.getEnvironment()
            .getPropertySources());
    addConfigFilesToEnvironment();
    Set<String> keys = changes(before,
            extract(context.getEnvironment().getPropertySources())).keySet();
    scope.refreshAll();

    context.publishEvent(new EnvironmentChangeEvent(keys));
}
@Configuration
protected static class Empty {

}

private void addConfigFilesToEnvironment() {
    ConfigurableApplicationContext capture = null;
    try {
        capture = new SpringApplicationBuilder(Empty.class).showBanner(false)
                .web(false).environment(context.getEnvironment()).run();
        MutablePropertySources target = context.getEnvironment().getPropertySources();
        for (PropertySource<?> source : capture.getEnvironment().getPropertySources()) {
            String name = source.getName();
            if (!standardSources.contains(name)) {
                if (target.contains(name)) {
                    target.replace(name, source);
                }
                else {
                    if (target.contains("defaultProperties")) {
                        target.addBefore("defaultProperties", source);
                    }
                    else {
                        target.addLast(source);
                    }
                }
            }
        }
    }
    finally {
        while (capture != null) {
            capture.close();
            ApplicationContext parent = capture.getParent();
            if (parent instanceof ConfigurableApplicationContext) {
                capture = (ConfigurableApplicationContext) parent;
            } else {
                capture = null;
            }
        }
    }
}

private Map<String, Object> changes(Map<String, Object> before,
                                    Map<String, Object> after) {
    Map<String, Object> result = new HashMap<String, Object>();
    for (String key : before.keySet()) {
        if (!after.containsKey(key)) {
            result.put(key, null);
        }
        else if (!equal(before.get(key), after.get(key))) {
            result.put(key, after.get(key));
        }
    }
    for (String key : after.keySet()) {
        if (!before.containsKey(key)) {
            result.put(key, after.get(key));
        }
    }
    return result;
}

private boolean equal(Object one, Object two) {
    if (one == null && two == null) {
        return true;
    }
    if (one == null || two == null) {
        return false;
    }
    return one.equals(two);
}

private Map<String, Object> extract(MutablePropertySources propertySources) {
    Map<String, Object> result = new HashMap<String, Object>();
    for (PropertySource<?> parent : propertySources) {
        if (!standardSources.contains(parent.getName())) {
            extract(parent, result);
        }
    }
    return result;
}

private void extract(PropertySource<?> parent, Map<String, Object> result) {
    if (parent instanceof CompositePropertySource) {
        try {
            for (PropertySource<?> source : ((CompositePropertySource) parent)
                    .getPropertySources()) {
                extract(source, result);
            }
        }
        catch (Exception e) {
            return;
        }
    }
    else if (parent instanceof EnumerablePropertySource) {
        for (String key : ((EnumerablePropertySource<?>) parent).getPropertyNames()) {
            result.put(key, parent.getProperty(key));
        }
    }
}
相關文章
相關標籤/搜索