ConfigServer是springcloud的一个组件-分布式配置中心,主要用于方便统一管理客户端配置,配置默认存放到git或者码云,尤其对于不同环境下的切换很方便。
主流的配置中心还有consul,阿波罗等。
一,原理与准备工作
在spring cloud config 组件中,分两个角色,一是config server,二是config client。
Config Server配置服务器,分布式配置中心,用于连接git为各个客户端拉取相应配置信息。
Config Client是Config Server的客户端,通过在启动配置文件中指定配置中心来获取相关配置。
而手动或者自动刷新配置需要用到spring cloud bus消息总线,来更新配置信息。原理如下:
客户端在启动时获取configserver从git拉取下来的配置信息,当git上的配置信息有所变动时,可以手动或者自动调用其中一个客户端的/actuator/bus-refresh接口(spring-boot2.x改成了这个接口),然后这个客户端获取最新配置并把更新的操作告诉bus消息总线,最后消息总线通知其他所有客户端进行刷爱操作。准备:
首先需要在git或者码云上创建一个仓库专门来存放客户端配置,在码云新建一个仓库-config-center,新建config文件夹,在config文件夹下新建user-client-dev.properties文件,完成后如图所示
这里要注意一下文件的命名规则,和工程的模块名对应,然后是生产环境,文件类型。即 /label/模块名/环境/yml或者properties配置结尾,label是分支,默认master,可不写。
/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
/{label}/{application}-{profile}.yml
另外还需要安装Rabbitmq,Rabbitmq需要erlang环境。安装好了需启动。
二,搭建配置中心
服务端配置:
创建好的Eurake服务注册中心,user测试模块(前篇创建好了),新增ConfigServer配置中心,如图所示:用到的是标红模块,其余没用
config-server是配置中心,首先引入configserver服务,同时将它注册到服务中心并引用ribbitmq与bus消息总线,需引包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
在application.properties中添加如下配置
server.port=8088
#服务名称,serverid
spring.application.name=config-server
##注册中心地址,把自己注册到注册中心
eureka.client.serviceUrl.defaultZone=http://localhost:8080/eureka/
#git配置仓库地址
spring.cloud.config.server.git.uri=https://gitee.com/wangToken0257443/config-center.git
#所在文件夹路径
spring.cloud.config.server.git.search-paths=config
#默认分支
spring.cloud.config.server.git.default-label=master
#强制获取
spring.cloud.config.server.git.force-pull=true
#rabbitmq相关信息
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=test
spring.rabbitmq.password=123456
#开放bus-refresh接口
management.endpoints.web.exposure.exclude=bus-refresh
启动类添加
@SpringBootApplication
@EnableConfigServer //配置中心
@EnableDiscoveryClient //注册客户端
客户端配置:
以客户端user模块为例:
引包,同理,客户端需要注册到注册中心,并且是config客户端,并需要引入消息总线,如图所示:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
##springcloud2.x用actuator通知刷新
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
添加配置:
新建bootstrap.yml或者bootstrap.properties配置文件,不能用applicaiton.yml或者application.properties配置文件,因为如果要从git获取相关配置,application.xx配置文件启动的优先级低于从git获取配置,所以用application.xx会报错获取不到Value{“代码中的配置key”},而用bootstrap.xx优先级是高的,可以正常获取配置。
这里新建了一个bootstrap.yml配置文件,和server的.properties不是一种,都试一试。
server:
port: 8082
spring:
application:
name: user-client #模块名称,对应git相关配置文件名称
cloud:
config:
profile: dev #配置环境
discovery:
enabled: true
service-id: config-server #指定config-server
label: master #分支
bus:
trace:
enabled: true
rabbitmq: #ribbitmq相关信息
addresses: localhost
port: 5672
username: test
password: 123456
eureka: #注册中心
client:
service-url:
defaultZone: http://localhost:8080/eureka/
management:
endpoints:
web:
exposure:
include: bus-refresh #开放/actuator/bus-refresh接口
endpoint:
health:
show-details: ALWAYS #显示详细健康检查信息
新建一个获取配置的测试类HelloController,同时新建一个配置实体类,如果直接在HelloController中以变量的形式获取git配置的话,只要添加@RefreshScope注解就会报错获取不到Value,boot2.x版本会报错,所以新建UserParams实体类,代码如下:主要用到的@RefreshScope注解放到这里,开启刷新
@Component
@RefreshScope
public class UserParams {
@Value("${myname}") #对应git user-client-dev.properties中的‘myname’key
private String myname;
public String getMyname() {
return myname;
}
public void setMyname(String myname) {
this.myname = myname;
}
}
在HelloController添加测试接口
@Autowired
private UserParams userParams;
@RequestMapping(value="getname")
private String hello(){
return userParams.getMyname();
}
浏览器访问http://localhost:8082/getname
这里获取到了对应的配置值,如果将git上配置值进行修改,发现刷新
http://localhost:8082/getname并没有变化,这里用postman访问http://localhost:8082/actuator/bus-refresh接口,成功后再次刷新http://localhost:8082/getname发现值变化。
将user客户端修改端口再启动一次,此时修改git上的配置再访问/actuator/bus-refresh接口会发现两个user程序获取的配置都变化了,只是没有自动而已自动刷新:
在码云或者git 仓库-管理-WebHooks添加一个webhook,webhook检测到配置有修改时会自动发送配置好的post接口访问,只要访问到自己项目的/actuator/bus-refresh接口,就可以实现自动刷新,我这里用花生壳做了外网穿透,所以地址是这个样子:
这里有一个点需要注意:可以发现我配置的webhook接口结尾是/bus-refresh2,并不是/bus-refresh,因为直接访问/actuator//bus-refresh是访问不到的,这里做了一个转发,在user的HelloController添加了如下代码:
@PostMapping("/actuator/bus-refresh2")
@ResponseBody
public Object busRefresh(HttpServletRequest request, @RequestBody(required = false) String s) {
return new ModelAndView("/actuator/bus-refresh");
}
到此为止,每次修改配置就会自动刷新所有客户端的配置了。不妥的是如果user客户端需要启动好几次,那么每个都会包含这个转发刷新的接口,并且刷新时先通知到客户端感觉很别扭。想法是弄一个专门的客户端用来通知刷新或者直接把刷新的配置放到configserver,感觉会好一点,有机会试一试