Spring Cloud 入門教程(二): 配置管理

使用Config Server,您可以在所有環境中管理應用程序的外部屬性。客戶端和服務器上的概念映射與Spring EnvironmentPropertySource抽象相同,因此它們與Spring應用程序非常契合,但可以與任何以任何語言運行的應用程序一起使用。隨着應用程序通過從開發人員到測試和生產的部署流程,您可以管理這些環境之間的配置,並確定應用程序具有遷移時需要運行的一切。服務器存儲後端的默認實現使用git,因此它輕鬆支持標籤版本的配置環境,以及可以訪問用於管理內容的各種工具。很容易添加替代實現,並使用Spring配置將其插入

以上是Spring Cloud官網對配置服務的描述, 簡單闡述一下我的理解。比如我們要搭建一個網站,需要配置數據庫連接,指定數據庫服務器的IP地址,數據庫名稱,用戶名和口令等信息。通常的方法, 我們可以在一個配置文件中定義這些信息,或者開發一個頁面專門配置這些東西。只有一個web服務器的時候, 很方便。

但假如需要搭建同多臺服務器時,當然可以每臺服務器做同樣配置,但維護和同步會很麻煩。我理解的配置服務至少有兩種不同場景:

1).  多個客戶使用同一配置: 比如,多臺服務器組成的集羣,假如後端使用同一數據庫,那麼每臺服務器都是用相同的配置。

2).  不同客戶使用不同的配置: 比如典型的場景是,開發,測試,生產使用相同的系統,但使用不同的數據庫

如果有個統一的根本配置,是不是就很方便,一個可行的辦法是,把這些配置文件放到一個共享存儲(比如網絡共享盤)中。這樣只需要在共享存儲修改一個或多個配置文件就可以了。但共享文件的方式受到具體佈署環境的限制,很多時候很難達到多臺Web服務器共享同一個存儲硬盤。

共享盤的缺點是資源定位比較困難,Spring Cloud的解決方案是, 將這些配置文件放到版本管理服務器裏面,Spring Cloud缺省配置使用GIT中。所有Web服務均從GIT中獲取這些配置文件。由於GIT服務器與具體Web服務器之間不需要共享存儲, 只要網絡可達就行,從而可以實現Web服務於配置信息的存放位置的解耦。

Spring Cloud統一控制應用和GIT服務的交互,應用只需要按照Spring Cloud的規範配置GIT的URL即可。 使用GIT後,場景2和場景1的區別僅僅是,場景2中不同的client使用不同版本的配置文件,但應用但訪問的文件看起來是會是同一個。Spring Cloud的配置服務結構入下圖

下面我們繼續上一節的例子Spring Cloud 入門之一. 服務註冊 繼續展開, 讓“Hello World”從配置文件helloworld.properties讀出,內容格式如下

hello=Hello World

其中關鍵字hello的值“Hello World”,就是我們要輸出的內容。

一. 創建config Server

 1.  創建Config Server, maven工程裏面配置spring-cloud-config-server

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

完整配置如下:

 

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 3     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 4   <modelVersion>4.0.0</modelVersion>
 5   <groupId>com.chry</groupId>
 6   <artifactId>springcloud.helloworld.config.server</artifactId>
 7   <version>0.0.1-SNAPSHOT</version>
 8   <packaging>jar</packaging>
 9   <name>helloworld.config.server</name>
10   <description>Demo Config Server</description>
11 
12     <parent>
13         <groupId>org.springframework.boot</groupId>
14         <artifactId>spring-boot-starter-parent</artifactId>
15         <version>1.5.3.RELEASE</version>
16         <relativePath/> <!-- lookup parent from repository -->
17     </parent>
18 
19     <properties>
20         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
21         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
22         <java.version>1.8</java.version>
23     </properties>
24 
25     <dependencies>
26         <!--eureka server -->
27         <dependency>
28             <groupId>org.springframework.cloud</groupId>
29             <artifactId>spring-cloud-starter-eureka</artifactId>
30         </dependency>
31         <dependency>
32             <groupId>org.springframework.cloud</groupId>
33             <artifactId>spring-cloud-starter-eureka-server</artifactId>
34         </dependency>
35         <dependency>
36             <groupId>org.springframework.cloud</groupId>
37             <artifactId>spring-cloud-config-server</artifactId>
38         </dependency>
39         <!-- spring boot test-->
40         <dependency>
41             <groupId>org.springframework.boot</groupId>
42             <artifactId>spring-boot-starter-test</artifactId>
43             <scope>test</scope>
44         </dependency>
45     </dependencies>
46 
47     <dependencyManagement>
48         <dependencies>
49             <dependency>
50                 <groupId>org.springframework.cloud</groupId>
51                 <artifactId>spring-cloud-dependencies</artifactId>
52                 <version>Dalston.RC1</version>
53                 <type>pom</type>
54                 <scope>import</scope>
55             </dependency>
56         </dependencies>
57     </dependencyManagement>
58 
59     <build>
60         <plugins>
61             <plugin>
62                 <groupId>org.springframework.boot</groupId>
63                 <artifactId>spring-boot-maven-plugin</artifactId>
64             </plugin>
65         </plugins>
66     </build>
67 
68     <repositories>
69         <repository>
70             <id>spring-milestones</id>
71             <name>Spring Milestones</name>
72             <url>https://repo.spring.io/milestone</url>
73             <snapshots>
74                 <enabled>false</enabled>
75             </snapshots>
76         </repository>
77     </repositories>
78 
79 </project>

2. 創建Config Server,它也是一個Spring Boot應用,@EnableConfigServer註解說明了一個Config Server。同樣我們使用@EnableEurekaClient將它註冊到服務中心。

 1 package springcloud.helloworld.config.server;
 2 
 3 import org.springframework.boot.SpringApplication;
 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
 5 import org.springframework.cloud.config.server.EnableConfigServer;
 6 import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
 7 
 8 @EnableEurekaServer
 9 @EnableConfigServer
10 @SpringBootApplication
11 public class ConfigServerApplication {
12     public static void main(String[] args) {
13         SpringApplication.run(ConfigServerApplication.class, args);
14     }
15 }

3. Config server的配置文件appication.yml , 注意配置文件的url是GIT服務器的倉庫地址, searchPaths配置文件所在的文件夾在倉庫中的路徑, 在server端不需要指定具體配置文件名, 因爲具體的配置文件是什麼有應用(也就是client)決定。

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8888

spring:
  cloud:
    config:
      server:
        git:
          uri: https://git.oschina.net/chrywhy/test
          searchPaths: spring-cloud/helloworldConfig
  application:
    name: config-server

4. 啓動config server後,訪問http://localhost:8888/abc/xyz, 可見如下響應。這個是輸出是並沒有包括具體配置文件的內容, 這個響應說明,config server可以正常訪問我們配置在application.yml中的GIT服務

這個URL是啥意思, 需要解釋一下。我們從輸出就可以看到 abc 就是application的名字,xyz是profile的名字, 注意這裏的abc, xyz均是隨便輸入的名字, 並不需要真實存在,config server這個REST接口返回的只是應用名爲abc, profile名爲xyz時,GIT配置環境的結構。

config server提供的REST接口,Spring Cloud官方文檔提供了幾個可選URL可以是如下幾個:

  1. /{application}/{profile}[/{label}]
  2. /{application}-{profile}.yml
  3. /{label}/{application}-{profile}.yml
  4. /{application}-{profile}.properties
  5. /{label}/{application}-{profile}.properties

比如 第三個格式,如果我們在GIT版本庫中有一個配置文件 spring-cloud/helloworldConfig/config-client-dev.properties. 那麼訪問http://localhost:8888/config-client-dev.properties就可以顯示配置文件內容。這個例子中, application的名字是"config-client"(也是下面我們即將創建的client), profile名字是dev, 文件後綴是.properties

本例由於配置了eureka服務中心,所以這個config server作爲一個eureka client註冊到了 eureka server中, 可以從http://localhost:8761看到我們啓動的config server, 如果不需要註冊到服務中心, 也可把這個配置去掉

 

 二. 創建config client

1.  創建maven工程, pom.xml如下:

 

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 3     <modelVersion>4.0.0</modelVersion>
 4     <groupId>com.chry</groupId>
 5     <artifactId>Springcloud.helloworld.config.client</artifactId>
 6     <version>0.0.1-SNAPSHOT</version>
 7     <name>Springcloud.helloworld.config.client</name>
 8     <packaging>jar</packaging>
 9     <description>Demo Spring Config Client</description>
10 
11     <parent>
12         <groupId>org.springframework.boot</groupId>
13         <artifactId>spring-boot-starter-parent</artifactId>
14         <version>1.5.3.RELEASE</version>
15         <relativePath/> <!-- lookup parent from repository -->
16     </parent>
17 
18     <properties>
19         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
20         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
21         <java.version>1.8</java.version>
22     </properties>
23 
24     <dependencies>
25         <dependency>
26             <groupId>org.springframework.cloud</groupId>
27             <artifactId>spring-cloud-starter-eureka</artifactId>
28         </dependency>
29         <dependency>
30             <groupId>org.springframework.boot</groupId>
31             <artifactId>spring-boot-starter-web</artifactId>
32         </dependency>
33         <dependency>
34             <groupId>org.springframework.cloud</groupId>
35             <artifactId>spring-cloud-starter-config</artifactId>
36         </dependency>
37         <dependency>
38             <groupId>org.springframework.boot</groupId>
39             <artifactId>spring-boot-starter-test</artifactId>
40             <scope>test</scope>
41         </dependency>
42     </dependencies>
43 
44     <dependencyManagement>
45         <dependencies>
46             <dependency>
47                 <groupId>org.springframework.cloud</groupId>
48                 <artifactId>spring-cloud-dependencies</artifactId>
49                 <version>Dalston.RC1</version>
50                 <type>pom</type>
51                 <scope>import</scope>
52             </dependency>
53         </dependencies>
54     </dependencyManagement>
55 
56     <build>
57         <plugins>
58             <plugin>
59                 <groupId>org.springframework.boot</groupId>
60                 <artifactId>spring-boot-maven-plugin</artifactId>
61             </plugin>
62         </plugins>
63     </build>
64 
65     <repositories>
66         <repository>
67             <id>spring-milestones</id>
68             <name>Spring Milestones</name>
69             <url>https://repo.spring.io/milestone</url>
70             <snapshots>
71                 <enabled>false</enabled>
72             </snapshots>
73         </repository>
74     </repositories>
75 
76 
77 </project>

2. 創建一個spring boot應用作爲client

 1 package springcloud.helloworld.config.client;
 2 
 3 import org.springframework.beans.factory.annotation.Value;
 4 import org.springframework.boot.SpringApplication;
 5 import org.springframework.boot.autoconfigure.SpringBootApplication;
 6 import org.springframework.web.bind.annotation.RequestMapping;
 7 import org.springframework.web.bind.annotation.RestController;
 8 
 9 @SpringBootApplication
10 @RestController
11 public class ConfigClientApplication {
12 
13     public static void main(String[] args) {
14         SpringApplication.run(ConfigClientApplication.class, args);
15     }
16 
17     @Value("${hello}")
18     String hello;
19     @RequestMapping(value = "/hello")
20     public String hello(){
21         return hello;
22     }
23 }

這個應用非常簡單,就是從Config Server中獲取配置項hello的值,Client Server向Config Server提交REST請求後,Config Server將訪問GIT服務器,並將取得的配置項hello的值返回給client.

3. Config client需要一個應用配置文件, 定義config Server的URL,以及要訪問的GIT具體分支。這個配置文件是bootstrap.yml (或者bootstrap.properties)

 1 spring:
 2   application:
 3     name: config-client
 4   cloud:
 5     config:
 6       label: master
 7       profile: dev
 8       uri: http://localhost:8888/
 9 server:
10   port: 8881

這個配置定義了應用的名字是config-client(這就是將要用於組裝前面Config Server一節中題到的application), profile採用dev, GIT分支用master。url是config server的地址。那麼問題來了,我們似乎沒定義配置文件名, 那配置文件名是什麼呢? 這點又體現了約定優於配置的思路, 這裏Spring Cloud約定, 應用的配置文件名以如下方式組成:{application}-{profile}.properties(或者{application}-{profile}.yml)。比如我們這個應用的配置文件就是config-client-dev.properties. 所以只需要在GIT的中創建配置文件spring-cloud/helloworldConfig/config-client-dev.properties就可以了, 內容如下:

hello=Hello World from GIT

 4. 啓動config-client應用後, 可以訪問http://locahost/8881/hello, 可以看到,應用本身並沒有直接配置hello的具體內容, 也沒指定具體配置文件,所欲這些都由spring cloud框架提交給config server了。

 

5.  配置的更新

至此,spring cloud的配置管理簡單示例已經完成,但client 不能自動感知服務端的變化。 比如,我們修改了GIT中的文件內容,但無論如何刷新client端的頁面,都不能反映配置的變化。下一節介紹Spring Cloud的配置自動更新機制

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章