spring cloud config服務器

Spring Cloud Config提供了一種在分佈式系統中外部化配置服務器和客戶端的支持。配置服務器有一箇中心位置,管理全部環境下的應用的外部屬性。客戶端和服務器映射到相同Spring Eventment 和 PropertySrouce抽象的概念,因此很是適合Spring應用,但也能夠在任何語言開發的任何應用中使用。在一個應用從開發、測試到生產的過程當中,你能夠分別地管理開發、測試、生產環境的配置,而且在遷移的時候獲取相應的配置來運行。java

 

準備工做git

準備幾個配置文件,命名規範爲 項目名稱-環境名稱.yml本文在git倉庫:https://github.com/xuwenjin中,新建目錄config-repo-xwj,建立如下幾個文件:
github

每一個文件內容以下:web

application.ymlspring

profile: profile-default

config-client.ymlapi

profile: config-client

config-client-dev.yml服務器

profile: dev

config-client-test.yml數據結構

profile: test

 

代碼示例app

建立一個Maven項目,在pom.xml文件中添加以下內容:eclipse

   <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Edgware.SR4</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <dependency>
            <!-- 解決啓動報Caused by: java.lang.ClassNotFoundException: org.eclipse.jgit.api.TransportConfigCallback -->
            <groupId>org.eclipse.jgit</groupId>
            <artifactId>org.eclipse.jgit</artifactId>
            <version>4.9.0.201710071750-r</version>
        </dependency>
    </dependencies>

啓動類:

@SpringBootApplication
@EnableConfigServer // 經過@EnableConfigServer註解激活配置服務
public class ConfigServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }

}

配置文件:application.yml

server:
  port: 18083
  
spring:
  application:
    name: config-server #應用程序名稱
  cloud:
    config:
      server:
        git:
          uri: https://github.com/xuwenjin/config-repo-xwj #git上,配置文件地址

這樣,一個Config Server就完成了。

 

測試工做

 規則中的參數含義以下:

  • {application}映射到客戶端的「spring.application.name」(項目名稱)
  •  {profile}映射到客戶端上的「spring.profiles.active」(環境名稱)
  •  {label}這是一個服務器端功能,標記「版本」的配置文件集(在git中,至關於分支名)

啓動服務,也能夠看到匹配規則:

先試下 {application}/{profile}[/{label}] 這個規則,請求路徑是 http://localhost:18083/config-client/dev/master,返回了全部配置文件信息:

另外四種規則差很少,可以使用如下路徑來訪問config-client-dev.yml文件,並直接返回其中的內容:

http://localhost:18083/config-client-dev.yml

http://localhost:18083/master/config-client-dev.yml

http://localhost:18083/config-client-dev.properties

http://localhost:18083/master/config-client-dev.properties

若是想要訪問config-client-test.yml文件,只須要將上面的 dev 換成 test 就行。

可是若是匹配不上呢?結果以下:

能夠看到,當匹配不上時,會默認讀取application.yml文件。

Config Server服務端是支持熱加載的,即不重啓服務的狀況下更改配置文件信息,是能夠直接讀取的

 

源碼分析

當發送請求時(如:http://localhost:18083/master/config-client-dev.yml ),會在 EnvironmentController 中進行匹配。以下:

@RestController
@RequestMapping(method = RequestMethod.GET, path = "${spring.cloud.config.server.prefix:}")
public class EnvironmentController {
    
    private EnvironmentRepository repository;
    
    // ...
    
    @RequestMapping({ "/{label}/{name}-{profiles}.yml", "/{label}/{name}-{profiles}.yaml" })
    public ResponseEntity<String> labelledYaml(@PathVariable String name, @PathVariable String profiles,
            @PathVariable String label, @RequestParam(defaultValue = "true") boolean resolvePlaceholders)
            throws Exception {
        // 校驗profiles是否含義"-",若是有則拋出異常
        validateProfiles(profiles);
        // 獲取環境信息,即遠程配置文件數據
        Environment environment = labelled(name, profiles, label);
        // 將environment對象轉爲Map
        Map<String, Object> result = convertToMap(environment);
        if (this.stripDocument && result.size() == 1 && result.keySet().iterator().next().equals("document")) {
            Object value = result.get("document");
            if (value instanceof Collection) {
                return getSuccess(new Yaml().dumpAs(value, Tag.SEQ, FlowStyle.BLOCK));
            } else {
                return getSuccess(new Yaml().dumpAs(value, Tag.STR, FlowStyle.BLOCK));
            }
        }
        String yaml = new Yaml().dumpAsMap(result);

        if (resolvePlaceholders) {
            yaml = resolvePlaceholders(prepareEnvironment(environment), yaml);
        }

        return getSuccess(yaml);
    }
    
    // ...

}

核心方法 labelled 中,會調用最核心的類 NativeEnvironmentRepositor findOne 方法:

@RequestMapping("/{name}/{profiles}/{label:.*}")
public Environment labelled(@PathVariable String name, @PathVariable String profiles,
        @PathVariable String label) {
    if (name != null && name.contains("(_)")) {
        // "(_)" is uncommon in a git repo name, but "/" cannot be matched
        // by Spring MVC
        name = name.replace("(_)", "/");
    }
    if (label != null && label.contains("(_)")) {
        // "(_)" is uncommon in a git branch name, but "/" cannot be matched
        // by Spring MVC
        label = label.replace("(_)", "/");
    }
    Environment environment = this.repository.findOne(name, profiles, label);
    return environment;
}

findOne方法會從遠程git倉庫中獲取配置文件數據:

@Override
public Environment findOne(String config, String profile, String label) {
    SpringApplicationBuilder builder = new SpringApplicationBuilder(
            PropertyPlaceholderAutoConfiguration.class);
    ConfigurableEnvironment environment = getEnvironment(profile);
    builder.environment(environment);
    builder.web(false).bannerMode(Mode.OFF);
    if (!logger.isDebugEnabled()) {
        builder.logStartupInfo(false);
    }
    String[] args = getArgs(config, profile, label);
    // 設置監聽器
    builder.application()
            .setListeners(Arrays.asList(new ConfigFileApplicationListener()));
    ConfigurableApplicationContext context = builder.run(args);
    environment.getPropertySources().remove("profiles");
    try {
        return clean(new PassthruEnvironmentRepository(environment).findOne(config,
                profile, label));
    }
    finally {
        context.close();
    }
}

獲取的Environment對象,數據結構以下:

能夠看到,配置文件信息,會放在 PropertySources 對象中~

相關文章
相關標籤/搜索