Spring Cloud 入門教程(二): 配置管理
使用Config Server,您可以在所有環境中管理應用程式的外部屬性。客戶端和伺服器上的概念對映與Spring Environment和PropertySource抽象相同,因此它們與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
- 建立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>
- 建立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 }
- 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
- 啟動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可以是如下幾個:
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{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
- 建立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>
複製程式碼
- 建立一個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.
- 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
-
啟動config-client應用後, 可以訪問http://locahost/8881/hello, 可以看到,應用本身並沒有直接配置hello的具體內容, 也沒指定具體配置檔案,所欲這些都由spring cloud框架提交給config server了。
-
配置的更新
至此,spring cloud的配置管理簡單示例已經完成,但client 不能自動感知服務端的變化。 比如,我們修改了GIT中的檔案內容,但無論如何重新整理client端的頁面,都不能反映配置的變化。下一節介紹Spring Cloud的配置自動更新機制