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:
<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文件
*/
//@EnableConfigServer注解用于开启Spring Cloud Config配置功能
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如下:
<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
*/
public class GetPropertyFromConfigServerController {
private static Logger logger = LoggerFactory.getLogger(GetPropertyFromConfigServerController.class);
("${com.springcloud.bruceliu.message}")
String message;
("/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);
public String[] getFileExtensions() {
return new String[]{"properties", "xml"};
}
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的高可用。