Spring Cloud专题之五:config
书接上回:
SpringCloud专题之一:Eureka
Spring Cloud专题之二:OpenFeign
Spring Cloud专题之三:Hystrix
Spring Cloud 专题之四:Zuul网关
随着服务越来越多,部署的集群越来越多,如果需要改某一个配置信息,那需要改动代码,打印成jar包,然后服务上线。这样维护的代价也太大了吧。这个时候就需要一个分布式的配置中心的组件了,实现代码和配置文件的解耦。
Spring Cloud Config主要为分布式系统中的基础设施合微服务应用提供集中化的外部配置支持。分为服务端喝客户端两个部分。其中服务端也称为分布式配置中心,用来连接配置仓库并为客户端提供获取配置信息、加密/解密信息等访问接口。客户端主要是微服务架构中的各个微服务应用或基础设施,通过指定的配置中心来管理应用资源与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置配置信息。
Spring Cloud Config实现的配置中心默认采用Git来存储配置信息,当然它也提供了对其他存储方式的支持,比如SVN仓库,本地化文件系统。
构建配置中心(config-server)
config-server的功能是:处理config client的请求,并访问Git,实现配置文件的饿查询,下载后在本地缓存,并将下载的配置发送到config client。
1.引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
2.开启Spring Cloud Config的服务端功能
/**
* EnableConfigServer:
* 开启spring cloud 中的config服务器,自动提供config服务器相关的功能,
* 启动时,同步启动taomcat,端口默认为8888,
* 一般配置中心服务器的端口定义为8888,因为config客户端默认查找的config服务器的地址是:
* http://localhost:8888/
*/
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
3.配置服务的相关信息
spring.application.name=config-server
server.port=8888
# 配置git的位置(建议大家用gitee测试,git在测试的过程中连不上是真的烦)
spring.cloud.config.server.git.uri=https://gitee.com/charon1798766775/spring_cloud_config_repo.git
# 配置仓库路径下的相对搜索位置,可以配置多个
#spring.cloud.config.server.git.search-paths=XXXXX
# 如果是私有仓库,需要设置访问git的用户名
#spring.cloud.config.server.git.username=XXXXX
# 如果是私有仓库,需要设置访问git的密码
#spring.cloud.config.server.git.password=XXXXX
这里我在git上创建了4个分支(master、env、test、prod),根据不同的环境创建不同的配置文件:
-
config.properties
my.config.server.name=charon
my.config.server.age=20
my.config.server.env=default
-
config-dev.properties
my.config.server.name=charon_dev
my.config.server.age=20
my.config.server.env=dev
-
config-test.properties
my.config.server.name=charon_test
my.config.server.age=20
my.config.server.env=test
-
config-prod.properties
my.config.server.name=charon_prod
my.config.server.age=20
my.config.server.env=prod
根据上面的映射文件,我们在可以直接通过restful api的方式进行访问配置,具体的路由规则如下:
- /{application}/{profile}[/{label}]
- /{application}-{profile}.yml
- /{label}/{application}-{profile}.yml
- /{application}-{profile}.properties
- /{label}/{application}-{profile}.properties
其中{label}对应的是Git上不同的分支,默认为master。比如我们需要访问test分支的内容,那么应该访问的url为:http://localhost:8888/config/test/test 。
三层访问规则:
- config:配置文件的名称
- test:配置文件的profiles,默认的为default
- test:分支名称
从上面返回的json中的内容可以看到有个version字段,它就是在git上的commit号。
config-server在从git上获取配置信息后,会存储一份在config-server的文件系统中,也就是config-server是通过git clone命令将配置内容复制了一份在本地存储,然后读取这些内容并返回给微服务应用进行加载。
config-server通过在本地暂存一份,可以防止GIt仓库出现故障而引起午发加载配置信息的情况。
客户端配置映射
下面我们尝试用服务获取配置信息。
1.引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
2.controller类
/**
* @className: ConfigClientController
* @description: 控制器
* @author: charon
* @create: 2021-07-31 16:18
*/
@RestController
public class ConfigClientController {
/**
* 配置文件中的name
*/
@Value("${my.config.server.name}")
private String name;
/**
* 配置文件中的age
*/
@Value("${my.config.server.age}")
private String age;
/**
* 配置文件中的env
*/
@Value("${my.config.server.env}")
private String env;
@GetMapping("/getConfig")
public String getConfig() {
return "返回配置文件中的数据:name=" + name + ";age=" + age + ";env=" + env;
}
}
3.配置文件
在这里使用bootstrap.properties配置文件作为配置中心。因为在spring boot启动时,bootstrap的配置文件是第一个加载的,优先级最高,然后才加载application的配置文件,最后加载application-profiles的配置文件。
spring.application.name=config-client
server.port=9011
# 需要配置spring cloud config server位置和要加载的相关参数
# spring cloud config server的连接地址
spring.cloud.config.uri=http://localhost:8888
# 要加载的配置文件主体命名
spring.cloud.config.name=config
# 要加载的配置文件所在的分支命名,默认为null,相当于master
spring.cloud.config.label=master
# 要加载的配置文件的profile,默认为default
spring.cloud.config.profile=default
获取配置的参数
这样是可以获取到配置中心的参数了,但是还有一个问题,就是如果配置文件发生了变更,服务还需要重启才能生效,那接下来就处理热刷新的问题。
热刷新
1.引入监控包:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2.配置文件
将相关管理以及健康管理端口暴露,spring boot2.0和spring boot1.0区别还挺大的
management.server.port=9012
management.endpoints.enabled-by-default=true
management.endpoints.web.base-path=/
management.endpoints.web.exposure.include=info,health,refresh
3.在controller类上,添加@RefreshScope注解,
@RefreshScope的作用:通知spring容器,热刷新的时候,重新刷新当前类型对应的所有对象,spring容器为提升热刷新效率,默认不刷新对象内容,只有明确指定的对象,才刷新。
4.将配置文件的my.config.server.age修改为50。
5.用postman发送post请求。
6.验证
config server除了使用git仓库外,还可以使用SVN仓库或者本地仓库做配置文件。
服务化配置中心
在Spring Cloud中,可以把config server视为微服务架构中与其他业务服务一样的一个基本单元。将config server注册到服务中心,并通过服务发现来访问config server并获取Git仓库中的配置信息。
在服务端和客户端分别加上eureka的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置eureka的地址
# 配置服务注册中心
eureka.client.serviceUrl.defaultZone=http://eureka-server1:9001/eureka/
在应用主类中,新增@EnableDiscoveryClient注解,用来将服务注册到上面配置的服务注册中心上去。
加密/解密
在实际项目中,往往存在大量的敏感信息,比如数据库账号与密码等一些信息。显然,如果直接以明文的方式存储在配置文件中是非常危险的。针对这一问题,Spring Cloud Config提供了对属性加密与解密的功能,以保护配置文件中的信息安全。
在Spring Cloud Config中通过在属性值前使用{cipher}前缀来标记该内容是一个加密值,当微服务客户端加载配置时,配置中心会自动为带有{cipher}前缀的值进行解密。通过这种机制,就可以不用担心敏感信息遭到泄露了。
1.使用前提
Java 中提供了一套用于实现加密、密钥生成等功能的包 JCE(Java Cryptography Extension),这些包提供了对称、非对称、块和流密码的加密支持,但是默认的 JCE 是一个有限长度的 JCE ,我们需要到 Oracle 官网去下载一个不限长度的 JCE :
jdk1.8不限长度JCE下载地址
下载完成后,将下载文件解压,解压后的文件包含如下三个文件:
将 local_policy.jar 和 US_export_policy.jar 两个文件拷贝到 JDK 的安装目录下,具体位置是 %JAVA_HOME%jrelibsecurity
,如果该目录下有同名文件,则直接覆盖即可。
2.配置密钥
我们可以通过encrypt.key属性在配置文件中直接指定密钥信息(对称性密钥),比如:
# 配置密钥
encrypt.key=666666
加入上面的配置信息后,重启配置中心,再访问localhost:8888/encrypt/status,可以看到有返回{"status":"OK"}
的内容。此时配置中心的加密解密功能就已经可以正常使用了。可以使用/encrypt和/decrypt来使用加密和解密功能了(post请求)。
加密:
解密:
下面我们在远程配置文件中的my.config.server.name的配置信息改为如下:
my.config.server.name={cipher}508d0eda835b6de26dcff97b75baf787c11d5cef5066999d1564af0d7f35e574
注意{cipher}不要忘记了,只有加上它才能解密。
在这里,我们通过配置encrypt.key参数来指定密钥的实现方式为对称性密钥。Spring Cloud Config的配置中心不仅可以使用对称性加密,也可以使用非对称性加密。
参考文章:
翟永超老师的《Spring Cloud微服务实战》
https://www.bilibili.com/video/BV1xV411e79Z?p=5&spm_id_from=pageDriver
https://www.cnblogs.com/shamo89/p/8016908.html
https://blog.csdn.net/qwe86314/article/details/101627446