1.簡介
在微服務中,每個功能模塊其實都可以拆分成一個單獨的服務實例,如果項目夠大,必然會有很多服務單元,每個服務單元都有一份配置文件需要維護,這顯得不太好維護,而且不方便協作開發。爲了使服務實例的配置文件統一管理化,Spring Cloud Config提供了一套解決方案,建立一個配置服務中心,每個服務單元從config server中獲取具體的配置文件,它支持配置服務放在配置服務的內存中(即本地),也支持放在遠程Git倉庫中。爲了保證系統的穩定,配置服務端config server可以進行集羣部署,即使某一個實例,因爲某種原因不能提供服務,也還有其他的實例保證服務的繼續進行。下面就講解一下Spring Cloud Config的基本用法。
遠程Git倉庫:存儲配置文件。
ConfigServer:分佈式配置管理中心,會於維護自己的git倉庫信息。
本地Git倉庫:在ConfigServer中,每次客戶端請求獲取配置信息時,都會從git倉庫獲取最新的配置到本地,然後本地讀取並返回,遠程無法獲取時,使用本地倉庫信息。
從上圖可以看出, Config Server 巧妙地通過 git clone 將配置信息存於本地,起到了緩存的作用,即使當 Git 服務端無法訪問的時候,依然可以取 Config Server 中的緩存內容進行使用。
2.準備工程
a. eurekaserver-7001: 服務註冊中心,端口7001
b. springcloud-config-server-8383: 高可用配置中心,端口8383
c. springcloud-config-client-8484 具體服務單元,端口8484
本文對怎麼搭建Eureka服務註冊中心不做過多講解,可以參考前面文章。
3.新建springcloud-config-server-8383工程
因爲要將配置中心作爲一個服務註冊到eureka中,所以注意引入config-server以及eureka的依賴,具體pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>springcloud0310</artifactId>
<groupId>com.bruceliu.springcloud0310</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-config-server-8383</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
4.啓動類加上@EnableConfigServer註解
@EnableConfigServer註解主要是開啓Spring Cloud Config分佈式配置的功能
package com.bruceliu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
/**
* 配置中心
* 證明配置服務中心是否可以從遠程程序獲取配置信息:
* 地址: localhost:8383/aaaa/dev實際是沒有對應的文件。如果真有文件,返回的json在會有propertySources屬性,它的值就是文件的內容。例如http://localhost:8383/config-client/dev 對應git倉庫中的config-client-dev.propeties文件
*/
@SpringBootApplication
//@EnableConfigServer註解用於開啓Spring Cloud Config配置功能
@EnableConfigServer
public class SpringcloudConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudConfigServerApplication.class, args);
}
}
@EnableDiscoveryClient : 讓config-server配置中心成爲eureka的服務端,通過負載均衡實現高可用
@EnableConfigServer: 開啓分佈式配置功能
5.git倉庫等屬性配置
首先創建一個放置配置文件的git倉庫,這裏是github,具體見下圖:
在git倉庫中新建一個repository(可以自定義名稱)文件夾,文件夾下面可以新建config-client-dev.properties、config-client-test.properties、config-client-prod.properties表示不同環境的配置文件。
config-client-dev.properties的內容爲:假設表示開發環境的配置文件
com.springcloud.bruceliu.message=Spring Cloud Config分佈式配置中心(開發環境)
config-client-test.properties的內容爲:假設表示測試環境的配置文件
com.springcloud.bruceliu.message=Spring Cloud Config分佈式配置中心(測試環境)
config-client-prod.properties的內容爲:假設表示生產環境的配置文件
com.springcloud.bruceliu.message=Spring Cloud Config分佈式配置中心(正式生產環境)
接下來配置application.properties:
#應用名稱
spring.application.name=config-server
#端口號
server.port=8383
#配置中心git倉庫地址,注意後面的/
spring.cloud.config.server.git.uri=對應你的git倉庫地址
#配置中心git倉庫路徑
spring.cloud.config.server.git.search-paths=repository
#訪問git倉庫的用戶名(如果Git倉庫爲公開倉庫,可以不填寫用戶名和密碼,如果是私有倉庫需要填寫)
spring.cloud.config.server.git.username=對應你的github用戶名
#訪問git倉庫的密碼
spring.cloud.config.server.git.password=對應你的github密碼
#配置git倉庫的分支
spring.cloud.config.label=master
注意:
spring.cloud.config.server.git.uri:指定配置中心git倉庫的地址
spring.cloud.config.server.git.search-paths: 指定配置中心倉庫的路徑,即創建的文件夾路徑
spring.cloud.config.label:指定git倉庫的分支
#訪問git倉庫的用戶名(如果Git倉庫爲公開倉庫,可以不填寫用戶名和密碼,如果是私有倉庫需要填寫)
spring.cloud.config.server.git.username: 指定訪問git倉庫的用戶名
spring.cloud.config.server.git.password:指定訪問git倉庫的密碼
6.啓動springcloud-config-server-8383
啓動完成之後,我們需要驗證一下配置服務中心是否可以從遠程程序獲取配置信息:
我們在瀏覽器訪問:http://localhost:8383/config-client/dev
或者 http://localhost:8383/master/config-client-dev.properties
或者 http://localhost:8383/config-client-dev.properties
:可以看到接口返回信息爲:
http://localhost:8383/config-client/dev
返回如下圖:
上圖所見,因爲git倉庫確實存在config-client-dev.properties配置文件,所以接口成功返回配置文件的內容,如果我們訪問http://localhost:8383/aaaa/dev,這時候就相當於查詢git倉庫中是否存在aaaa-dev.properties這個配置文件,如果不存在,返回的propertySources爲空,但是也可以驗證我們可以從遠程git倉庫獲取配置文件的內容,簡單理解就是我們在服務單元中跟git倉庫是連通的。
http://localhost:8383/master/config-client-dev.properties返回
http://localhost:8383/config-client-dev.properties返回:
可以看到,接口成功返回數據,說明我們可以從遠程git倉庫獲取到配置文件的信息。(忽略中文亂碼問題,後面會講解決方法,這裏只是驗證是否可以從遠程git倉庫獲取到配置文件的信息)
擴展:
URL與配置文件的映射關係如下:(主要有五種)
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
#label:表示git倉庫的分支
#application:表示具體服務單元的名稱,即後面config-client的application-name
#profile: 指定環境類型
dev-開發環境
prod-生產環境
test-測試環境
經過以上步驟,我們的config-server就算搭建成功了。下面我們搭建config-client
7.新建springcloud-config-client工程
引入spring-cloud-starter-config依賴,具體pom.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>springcloud0310</artifactId>
<groupId>com.bruceliu.springcloud0310</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-config-client-8484</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
8.confing-client配置文件bootstrap.properties
注意:新建bootstrap.properties
,不是application.properties
#應用名稱(對應的git倉庫配置文件名稱也應該是:config-client-dev、config-client-prod、config-client-test)
spring.application.name=config-client
#端口
server.port=8484
#配置git遠程倉庫的分支
spring.cloud.config.label=master
#配置服務中心地址(即config-server的地址)
spring.cloud.config.uri=http://localhost:8383/
#配置環境
#dev爲開發環境配置文件
#test爲測試環境
#pro爲正式環境
spring.cloud.config.profile=test
注意:
spring.cloud.config.label:指定git倉庫的分支
spring.cloud.config.uri: 指定配置服務中心地址(即config-server的地址)
spring.cloud.config.profile=dev:指定所屬環境
spring.application.name=config-client:應用名稱(對應的git倉庫配置文件名稱也應該是:config-client-dev、config-client-prod、config-client-test)
9.新建GetPropertyFromConfigServerController
主要是暴露一個接口用於測試從遠程git倉庫獲取配置文件的內容
package com.bruceliu.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 測試客戶端從配置服務中心獲取配置文件中的內容
*
* @author weishihuai
* @date 2018/9/17 22:05
*/
@RestController
public class GetPropertyFromConfigServerController {
private static Logger logger = LoggerFactory.getLogger(GetPropertyFromConfigServerController.class);
@Value("${com.springcloud.bruceliu.message}")
String message;
@RequestMapping("/getPropertyFromConfigServer")
public String getPropertyFromConfigServer() {
System.out.println(message);
String msg = "hello, i am " + message + ", i'm come from config server";
logger.info(msg);
return msg;
}
}
10.啓動config-server以及config-client
瀏覽器訪問http://localhost:8484/getPropertyFromConfigServer,
可以看到,我們成功從git遠程倉庫中獲取了config-client-dev配置文件中的內容。可以看到中文出現亂碼了,出現亂碼的原因:
spring默認加載配置文件load方法中使用的是IOS-8859-1編碼格式,解決方法:改造springcloud-config-server服務配置中心
a. 需要重寫一個自定義的PropertySourceLoader,指定編碼格式爲utf-8:
package com.bruceliu.encode;
import org.apache.logging.log4j.util.PropertiesPropertySource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.*;
/**
* @Title: CustomPropertySourceLoader
* @ProjectName springcloud_confing_center
* @Description: 自定義PropertySourceLoader解決中文亂碼問題
*/
public class CustomPropertySourceLoader implements PropertySourceLoader {
private static final Logger logger = LoggerFactory.getLogger(CustomPropertySourceLoader.class);
@Override
public String[] getFileExtensions() {
return new String[]{"properties", "xml"};
}
@Override
public List<PropertySource<?>> load(String name, Resource resource) throws IOException {
/*List<PropertySource<?>> propertySourceList = new ArrayList<PropertySource<?>>();
Properties properties = getProperties(resource);
if (!properties.isEmpty()) {
PropertiesPropertySource propertiesPropertySource = new PropertiesPropertySource(name, properties);
propertySourceList.add(propertiesPropertySource);
}
return propertySourceList;*/
Map<String, ?> properties = loadProperties(resource);
if (properties.isEmpty()) {
return Collections.emptyList();
}
return Collections
.singletonList(new OriginTrackedMapPropertySource(name, properties));
}
private Map<String, ?> loadProperties(Resource resource) {
Properties properties = new Properties();
InputStream inputStream = null;
try {
inputStream = resource.getInputStream();
properties.load(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
inputStream.close();
} catch (IOException e) {
logger.error("load inputstream failure...", e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
logger.error("close IO failure ....", e);
}
}
}
return (Map) properties;
}
}
b.在resources文件夾下面創建META-INF文件夾,新建一個spring.factories文件,文件內容爲
#指定自定義PropertySourceLoader,注意是全路徑
org.springframework.boot.env.PropertySourceLoader=com.bruceliu.encode.CustomPropertySourceLoader
重啓config-server,config-client,瀏覽器訪問
可以看到,中文正常顯示了,亂碼問題解決。
以上我們只是測試讀取dev開發環境的配置文件內容,下面我們再測試一個讀取test環境的配置文件:
修改config-client的bootstrap.properties中的spring.cloud.config.profile=test指定爲測試環境,
重啓項目,瀏覽器訪問http://localhost:8484/getPropertyFromConfigServer,
可以看到,現在讀取的就是測試環境下的配置文件信息。至此,我們實現了一個比較簡單的config-server以及config-client,實現了從遠程git倉庫獲取各個環境對應的配置文件信息。
11.總結
在實際項目中,config server配置中心通常需要集羣部署,這樣某個配置中心掛掉也不會影響到其他服務單元的正常使用。本章搭建的config server並不是高可用的,下一章將會講解config- server的高可用。