介绍
Spring Cloud Config项目是一个解决分布式系统的配置管理方案。它包含了Client和Server两个部分,server提供配置文件的存储、以接口的形式将配置文件的内容提供出去,client通过接口获取数据、并依据此数据初始化自己的应用。Spring cloud使用git或svn存放配置文件,默认情况下使用git。
Spring Cloud Config主要功能:
- 集中管理各环境、各个服务的配置文件
- 提供服务端和客户端支持
- 配置文件修改后,可以快速生效
- 配置文件通过git/svn进行管理,天然支持版本回退功能
- 支持高并发查询,也支持各种开发语言
接下来以git为例做一个示例。
git示例
准备
github创建一个名为configRepoTest的仓库。将准备的文件上传到仓库,文件内容看仓库(https://github.com/xiaoxiaoshou/configRepoTest)。
server端
创建一个springboot项目。
1.依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
2.启动类添加注解
@SpringBootApplication
@EnableConfigServer
public class ConfigserverApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigserverApplication.class, args);
}
}
3.配置文件application.yml
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://github.com/xiaoxiaoshou/configRepoTest
search-paths: client1 # 仓库中配置文件的目录
username: github用户名
password: github密码
server:
port: 8081
search-paths对应的值也可以用占位符配置search-paths: {application}
4.启动测试
输入http://localhost:8081/config-server/dev获取dev配置信息。如果直接查看dev配置文件中的配置信息可访问http://localhost:8081/client1-dev.properties。
实际上访问地址如下规则:
- /{application}/{profile}[/{label}]
- /{application}-{profile}.yml
- /{label}/{application}-{profile}.yml
- /{application}-{profile}.properties
- /{label}/{application}-{profile}.properties
application表示配置文件名
profile表示配置文件profile,例如test、dev、prod
label表示git分支,参数可选默认就是master
Client端
1.依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2.配置文件
- application.yml
spring:
application:
name: config-client
server:
port: 8082
- bootstrap.yml
spring:
cloud:
config:
name: client1
profile: dev
label: master
uri: http://localhost:8081
注意:上面这些与Springcloud相关的属性必须配置在bootstrap.yml,config部分内容才能被正确加载。因为config的相关配置会先于application.yml,而bootstrap.yml的加载也是先于application.properties。
3.控制层提供测试接口
@RestController
public class HelloController {
@Value("${pikachues}")
String pikachues;
@GetMapping("/hello")
public String hello(){
return this.pikachues;
}
}
注意上面配置的pikachues这个名称是github上配置的key名称,如果不是启动会报错。
启动项目访问:http://localhost:8082/hello即可看到你github上配置key对应的值,我这里是返回dev。
扩展
虽然在实际开发中,配置文件一般都是放在git仓库中,但是,Config-server也支持将文件放在classpath下。
配置文件添加如下配置即可实现:
spring:
profiles:
active: native # 表示让config-server从classpath下查找配置,而不是去github查找
cloud:
config:
server:
native:
search-locations: file:/E:/properties/ # 指定配置文件的位置
动态刷新
在上面git示例中你会发现,当github中的配置文件发生变化时,server端获取的是最新的信息,而client端获取的是旧的配置信息,也就是说server端可以及时感知到配置信息的变化,而client不能及时感知到配置文件的变化。默认情况下client端只有重启才能加载到最新的配置文件。要实现动态刷新步骤如下:
1.添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2.application.yml中添加如下配置,使refresh端点暴露出来
management:
endpoints:
web:
exposure:
include: refresh
3.在client端使用了配置文件的地方加上@RefreshScope注解
加上注解后,当配置文件改变后只要调用refresh端点,client端中的配置就可以刷新。
@RestController
@RefreshScope
public class HelloController {
@Value("${pikachues}")
String pikachues;
@GetMapping("/hello")
public String hello(){
return this.pikachues;
}
}
配置成功后重启client端,以后只要配置文件发生变化,发送post请求调用http://localhost:8082/actuator/refresh接口配置文件就会自动刷新。这里虽然可以动态刷新,但是有一个问题:每一个client都要发送一个请求才能刷新其配置数据。
请求失败重试
client端在调用server端时,可能发生调用失败的情况,那么我们可以配置一个请求重试的功能。
1.添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
2.配置文件
spring:
cloud:
config:
# 开启快速响应(主要)
fail-fast: true
retry:
# 请求重试的初始间隔时间
initial-interval: 1000
# 最大重试次数
max-attempts: 6
# 重试时间间隔
multiplier: 1.1
# 最大间隔时间
max-interval: 2000
配置完成后重启,以上配置完成后即可实现请求失败重试。
配置文件加解密
常见加密方案
- 不可逆加密
- 可逆加密
不可逆加密,就是理论上无法根基加密后的密文推出明文。一般用在密码加密上,常见的算法如MD5信息摘要算法、SHA安全散列算法。
可逆加密,看名字就知道可以根据加密后的密文推出明文,可逆加密算法又分为两种:
- 对称加密
- 非对称加密
对称加密指加密的秘钥和解密的秘钥是一样的。常见算法des、3des、aes。
非对称加密就是加密的秘钥和解密的秘钥是不一样的,加密的叫做公钥,可以告诉任何人,解密的叫做私钥,只有自己知道。常见算法RSA。
对称加密
java中要利用对称加密首先要下载JCE,下载地址:https://www.oracle.com/java/technologies/javase-jce8-downloads.html
将下载的文件解压,解压出来的jar拷贝到java安装目录中:…\lib\security\。如果jdk中没有…\lib\security\就拷贝到jre的对应目录中。
然后在configserver的bootstrap.yml配置文件中添加如下配置:
# 秘钥
encrypt:
key: pikachues
然后启动configserver,访问http://localhost:8081/encrypt/status查看秘钥配置是否ok。
接下来,带上你要加密的明文访问http://localhost:8081/encrypt获取密文,将获取的密文存储到git仓库中,注意存储时要加{cipher}前缀。
这时你可以通过访问:http://localhost:8081/client1/dev获取对应的配置信息,也可以通过启动configclient访问:http://localhost:8082/hello获取对应的配置信息。
非对称加密
要使用非对称加密,首先我们要生成一个秘钥。
在命令行执行如下命令生成keystore
:
keytool -genkeypair -alias config-server -keyalg RSA -keystore E:config-server.keystore
命令执行完成后,拷贝生成的keystore文件到configserver的resources目录下。
然后在configserver的bootstrap.yml配置文件中添加如下配置:
encrypt:
key-store:
alias: config-server
location: config-server.keystore
password: 111111
secret: 111111
接下来重启configserver,测试方法与对称加密一致。
如果访问http://localhost:8081/encrypt/status检测配置信息是不ok,那么可能原因是keystore文件被过滤掉了。
在pom.xml文件中build节点中添加如下配置防止keystore被过滤:
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.keystore</include>
</includes>
</resource>
</resources>
安全管理
为了防止用户直接通过访问configserver看到配置文件的内容,我们可以用spring security来保护configserver接口。
首先在configserver中添加security依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
添加完依赖,configserver中的接口就自动保护起来了。
为了方便使用,我们可以在configserver中配置自己的用户名密码。
在configserver的bootstrap.yml配置文件中添加如下配置固定用户名密码:
spring:
security:
user:
name: admin
password: 123
configserver的接口被保护起来后,configclient无法直接访问,因此启动会报错,因此应该在configclient的配置文件bootstrap.yml中添加如下配置:
spring:
cloud:
config:
username: admin
password: 123
服务化
前面的配置都是在configclient中写死configserver地址。这里将configclient和configserver都注册到服务中心,configclient中只需配置configserver名称即可。
准备
准备一个eureka注册中心。
依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
配置:
server:
port: 8083
eureka:
client:
fetch-registry: true
register-with-eureka: false
service-url:
defaultZone: http://localhost:8083/eureka
spring:
application:
name: eureka-server-bus
配置好之后启动项目。
实行
首先分别给configserver和configclient加上eureka客户端依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
然后在configserver和configclient分别配置注册信息
eureka:
client:
service-url:
defaultZone: http://localhost:8083/eureka
这里eureka配置信息configclient要配置到bootstrap.yml配置文件中,否则可能启动报错Cannot execute request on any known server
,并且访问的接口是http://localhost:8888
然后修改configclient中的配置文件,不再写死configserver地址
spring:
cloud:
config:
name: client1
profile: dev
label: master
# 直接写死破坏了微服务架构
# uri: http://localhost:8081
username: admin
password: 123
discovery:
# 开启通过eureka获取configserver功能
enabled: true
# 配置configserver服务名称
service-id: config-server-bus
这时候可以启动项目了,但是由于加入了eureka-client,启动configserver可能会报错,解决办法是重新生成一个jks格式的秘钥。
keytool -genkeypair -alias mytestkey -keyalg RSA -keypass 111111 -keystore E:config-service.jks -storepass 111111
生成秘钥之后将秘钥拷贝到configserver的resources目录下,同时修改bootstrap.yml配置文件
# 秘钥
encrypt:
# key: pikachues
key-store:
alias: mytestkey
location: classpath:config-service.jks
password: 111111
secret: 111111
到这里服务化配置完成,可以按前面的方法重启测试。
项目地址