资料参考:《Spring Cloud 微服务实战》
目录
uri指定配置中心(Config First Bootstrap)
服务化配置中心(Discovery First Bootstrap)
客户端详解
uri指定配置中心(Config First Bootstrap)
spring cloud config
的客户端在启动的时候,默认会从工程的classpath
中加载配置信息并启动应用。只有当我们配置spring.cloud.config.uri
的时候,客户端应用才会尝试连接spring cloud config
的服务端来获取远程配置信息并初始化spring环境配置。同时,我们必须将该参数配置在bootstrap.yml
,环境变量或是其他优先级高于应用jar包内的配置信息中,才能正确加载到远程配置。若不指定spring.cloud.uri
参数的话,spring cloud config
的客户端会默认尝试连接http://localhost:8888
。
spring:
application:
name: zhihaomiao
cloud:
config:
uri: http://localhost:9090/
profile: pro
label: config-label-test
服务化配置中心(Discovery First Bootstrap)
config server
注册到服务中心,并被其他应用所发现实现配置信息获取。我们把config server
看作一个微服务。
对快速入门进行改造:
服务端配置:
- 在config-server的pom.xml总增加eureka依赖,如下:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
- 在application.yml中配置注册eureka的相关参数:
# 安全验证,指定验证得用户名和密码
security:
basic:
enabled: true
user:
name: user
password: root123456
# git配置
spring:
application:
name: config-server-git
cloud:
config:
server:
git:
uri: http://git.oschina.net/zhihaomiao/{application}-config
username: zhihao.miao
password: 13579qwertyu
server:
port: 9090
# 加密与解密
encrypt:
key: zhihao.miao
# eureka配置,配置中心作为服务
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
instance:
instance-id: ${spring.application.name}:${spring.cloud.client.ipAddress}:${spring.application.instance_id:${server.port}}
prefer-ip-address: true
- 在应用主类中,新增
@EnableDiscoveryClient
注解,用来将config-server
注册到配置中心
@EnableDiscoveryClient
@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class,args);
}
}
- 启动
eureka
服务,可以看到config-server
在eureka
控制面板的信息。
客户端配置:
- 在
order-service
的pom中新增了eureka
依赖,以实现客户端发现config-server
服务,具体依赖如下:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
- 在bootstrap.yml中,按如下配置:
spring:
application:
name: order-service
cloud:
config:
discovery:
enabled: true # 开启通过服务来访问配置中心
service-id: config-server-git # 指定服务名
username: user # 安全校验,使用在配置中心配置得用户名和密码
password: root123456 # 安全校验,使用在配置中心配置得用户名和密码
profile: pro
label: master
server:
port: 6060
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
instance:
instance-id: ${spring.application.name}:${spring.cloud.client.ipAddress}:${spring.application.instance_id:${server.port}}
prefer-ip-address: true
其中,通过eureka.client.service-url.defaultZone
参数指定服务注册中心,用于服务的注册与发现,将spring.cloud.config.discovery.enabled
参数设置为true
,开启通过服务来访问config server
的功能;spring.cloud.config. discovery.service-id
参数来指定config server
注册的服务名。这里的spring.application.name
和spring.cloud.config.profile
和之前一样,定位git中的资源。
- 应用主类上加上@EnableDiscoveryClient注解,用来发现config-server-git的服务,利用其发现服务进行加载应用配置:
@EnableDiscoveryClient
@SpringBootApplication
public class ConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class,args);
}
}
官网中还有这一段:
The discovery client implementations all support some kind of metadata map (e.g. for Eureka we have eureka.instance.metadataMap). Some additional properties of the Config Server may need to be configured in its service registration metadata so that clients can connect correctly. If the Config Server is secured with HTTP Basic you can configure the credentials as "username" and "password". And if the Config Server has a context path you can set "configPath". Example, for a Config Server that is a Eureka client:
服务发现客户端实现都支持一些元数据映射(例如,对于Eureka,我们有eureka.instance.metadataMap
配置)。 可能需要在其服务注册元数据中配置Config Server的一些其他属性,以便客户端可以正确连接。 如果使用HTTP Basic安全配置服务器,则可以将凭据配置为“用户名”和“密码”。 并且如果配置服务器具有上下文路径,您可以设置“configPath”。 例如,对于作为Eureka客户端的配置服务器:
bootstrap.yml
eureka:
instance:
...
metadataMap:
user: osufhalskjrtl
password: lviuhlszvaorhvlo5847
configPath: /config
在我的理解就是服务注册的客户端与服务注册服务端进行数据交互验证的时候可以使用这个属性
失败快速响应与重试
spring cloud config
的客户端会预先加载很多其他信息,然后再开始连接config server
进行属性的注入,当我们构建的应用比较复杂的时候,可能在连接config server
之前花费太多的启动时间,而在一些特殊的场景下,我们希望可以快速知道当前应用是否能顺利地从config server
获取到配置信息,这对在初期构建调试环境时,可以减少很多等待启动的时间。要实现客户端优先判断config server
获取是否正常,并快速响应失败内容,只需在bootstrap.yml
中配置参数spring.cloud.config.failFast=true
即可。
测试一下,在没有该参数前,不启动config server
,直接启动客户端应用,可以获得下面的报错信息,同时,在报错之前,可以看到客户端应用已经加载了很多内容,比如controller的请求,只有在属性注入的时候报错了,
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'configClientController': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'spring.datasource.username' in value "${spring.datasource.username}"
加上spring.cloud.config.failFast=true
参数之后,再启动客户端应用,可以获得下面的报错信息,并且前置的加载内容少了很多,这样通过该参数有效避免了当config server
配置有误时,不需要多等待前置的一些加载时间,实现快速失败信息。
java.lang.IllegalStateException: Could not locate PropertySource and the fail fast property is set, failing
at org.springframework.cloud.config.client.ConfigServicePropertySourceLocator.locate(ConfigServicePropertySourceLocator.java:130) ~[spring-cloud-config-client-1.2.3.RELEASE.jar:1.2.3.RELEASE]
at org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration.initialize(PropertySourceBootstrapConfiguration.java:89) ~[spring-cloud-context-1.1.9.RELEASE.jar:1.1.9.RELEASE]
at org.springframework.boot.SpringApplication.applyInitializers(SpringApplication.java:636) [spring-boot-1.4.5.RELEASE.jar:1.4.5.RELEASE]
at org.springframework.boot.SpringApplication.prepareContext(SpringApplication.java:350) [spring-boot-1.4.5.RELEASE.jar:1.4.5.RELEASE]
上面,我们演示了当config server宕机或是客户端配置不正确导致连接不到而启动失败的情况,快速响应的配置可以发挥比较好的效果。但是,若只是因为网络波动等其他间歇性原因导致的问题,直接启动失败似乎代价有点高。所以,config客户端还提供了重试的功能,在开启重试功能前,先确保已经配置了spring.cloud.config.failFast=true
,在进行下面的操作:
- 在
pom.xml中增加spring.retry
和spring-boot-starter-aop
依赖:
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
不需要做其他任何配置,启动客户端应用,在控制台中可以看到如下内容,客户端连接config server
失败之后,继续尝试,直到第6次失败后,才返回错误信息。通过这样的重试机制,可以避免一些间歇性问题引起的失败导致客户端应用无法启动的情况。
2017-08-18 18:29:44.142 INFO 55961 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at: http://localhost:8888
2017-08-18 18:29:45.211 INFO 55961 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at: http://localhost:8888
2017-08-18 18:29:46.345 INFO 55961 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at: http://localhost:8888
2017-08-18 18:29:47.578 INFO 55961 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at: http://localhost:8888
2017-08-18 18:29:48.923 INFO 55961 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at: http://localhost:8888
2017-08-18 18:29:50.399 INFO 55961 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at: http://localhost:8888
2017-08-18 18:29:50.405 WARN 55961 --- [ main] o.s.boot.SpringApplication : Error handling failed (ApplicationEventMulticaster not initialized - call 'refresh' before multicasting events via the context: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@1d61c6dc: startup date [Thu Jan 01 08:00:00 CST 1970]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@3af9c5b7)
2017-08-18 18:29:50.413 ERROR 55961 --- [ main] o.s.boot.SpringApplication : Application startup failed
如果是配置具体的uri的话那么就会重试6次的uri配置,如果是配置的eureka
注册的话,就会发6次http://localhost:8888
失败。
若对默认的最大重试次数和重试间隔等设置不满意,还可以通过下面的参数进行调整:
spring.cloud.config.retry.multiplier
:初始重试间隔时间(单位为毫秒),默认是1000毫秒。spring.cloud.config.retry.initial-interval
:下一个间隔的乘数,默认是1.1,所以当最初间隔式1000毫秒时,下一次失败后的间隔为1100毫秒。spring.cloud.config.retry.max-interval
:最大间隔时间,默认是2000毫秒。spring.cloud.config.retry.max-attempts
:最大重试次数,默认为6次。
获取远程配置
在快速入门中,我们对 {application}
, {profile}
, {label}
这些参数已经有了一定的了解。在git仓库中,一个形如 {application}-{profile}.properties
或是 {application}-{profile}.yml
的配置文件,通过uri请求和客户端配置访问对应可以总结如下:
- 通过向config-server发送get请求以直接的方式获取,可用下面的链接形式:
不带{label}分支信息,默认访问master分支,可使用
- /{application}-{profile}.yml
- /{application}-{profile}.properties
带{label}分支信息,可使用:
- /{label}/{application}-{profile}.yml
- /{application}/{profile}[/{label}]
- /{label}/{application}-{profile}.properties
- 通过客户端配置方式加载的内容如下所示
- spring.application.name: 对应配置文件中的{application}内容
- spring.application.profile: 对应配置文件中{profile}内容
- spring.application.config.label: 对应分支内容,如不配置,默认为master
动态刷新配置
有时候需要对配置内容做些实时更新,那么spring cloud config
是否可以实现呢?肯定是可以的,下面对快速入门进行一些改造.
回顾一下快速入门,
config-repo-demo
:在git上新建的一项目模块,只要是做配置中心的,其中存储了应用名为zhihao
的多环境配置文件,配置文件中有二个配置参数from
和spring.datasource.name
config-server-git
:配置了git仓库的服务端config-client
: 指定了config-server
为配置中心的客户端,应用名为zhihao
,用来访问配置服务器以获取配置信息。该应用中提供了一个/index
接口,访问config-repo-demo/zhihao.yml
中的from
和spring.datasource.name
属性,
当前配置文件:
from: git-pro-2.0
spring:
datasource:
username: user_pro
在线修改之后,
from: git-pro-3.0
spring:
datasource:
username: user_pro3
测试,http://localhost:8080/index
发现访问客户端的接口,页面显示还是username=user_pro,form==git-pro-2.0
接下来,我们将config-client端做一些改造以实现配置信息的动态刷新。
- 在
config-client
的pom文件中新增spring-boot-starter-actuator
监控依赖,其中包含/refresh
端点的实现,该端点将用于实现客户端应用配置信息的重新获取与刷新。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
- 在客户端上需要注入配置值的类上加入注解
@RefreshScope
@RestController
@RefreshScope
public class ConfigClientController {
private Logger log = LoggerFactory.getLogger(getClass());
@Value("${spring.datasource.username}")
private String username;
@Value("${from}")
private String from;
@GetMapping("/index")
public String index(){
log.info("username="+username+",form=="+from);
return "username="+username+",form=="+from;
}
}
- 重新访问
config-client
,访问一次可以看到当前的配置 - 修改git上的配置
- 在次访问
http://localhost:8080/index
,看到配置信息没有改变 - 通过post请求发送到
localhost:8080/refresh
,可以看到返回的内容
➜ curl -X POST http://localhost:8080/refresh
["config.client.version","spring.datasource.username","from"]
- 再次访问
http://localhost:8080/index
,看到更新后的值了
username=user_pro3.0,form==git-pro-3.0
通过上面的介绍,该功能还可以同git仓库的web hook功能进行关联,当有git提交变化时,就给对应的配置主机发送/refresh
请求来实现配置信息的实时更新。但是,当我们的系统发展壮大之后,维护这样的刷新清单也将成为一个非常大的负担,而且很容易犯错,可以使用spring cloud bus
来解决这个问题。
git地址:https://github.com/servef-toto/SpringCloud-Demo/tree/master/config-server-file/git-config