- 在学习spring cloud的时候我们就说了,它是一个C/S架构,所以我们至少写两个服务,一个是server,一个是client
1.spring cloud config 服务端实现
- 先创建server模块:springcould-config-server-3344
- 导入依赖
<dependencies> <!--config--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> <version>2.2.5.RELEASE</version> </dependency> </dependencies>
- 编写配置文件
#设置微服务运行端口 server: port: 3344 #标识微服务名称 spring: application: name: springcould-config-server #连接远程仓库的配置 cloud: config: server: git: uri: https://gitee.com/thhhstudy/springcloud-config.git #直接去远程仓库上复制地址,注意使用的是HTTPS,不再是使用git本地克隆的时候使用的SSH,原因就是正常分布式中微服务连接都是基于HTTP的 #注意是URI不是URL
- 编写主启动类,注意使用注解@EnableConfigServer 开启config配置服务端
package com.thhh.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.config.server.EnableConfigServer; @SpringBootApplication @EnableConfigServer //开启config配置服务端 public class ConfigServer_3344 { public static void main(String[] args) { SpringApplication.run(ConfigServer_3344.class,args); } }
- 测试
- 可见现在我们就可以通过创建的config的服务端获取远程仓库上的配置文件,注意:我们也只能获取到配置文件,因为spring cloud config分布式配置本来就是用来集中管理配置文件的,不是管理所有文件的
- 服务端的作用就相当于这个微服务作为了远程仓库,我们可以通过它获取到远程仓库中的配置文件
- 官方文档指出,除了使用上面例子中的URL获取到仓库中配置文件,还可以使用其他的形式获取到配置文件资源
- 可见不同的访问URL得到的数据资源格式不一样,数据也有一些不一样
2.spring cloud config 客户端实现
- 客户端就是服务提供者对应的微服务模块,在spring cloud config中,客户端需要从spring cloud config服务端获取配置文件的信息
- 在本地仓库中创建一个新的yml配置文件,作为等会儿写的服务提供者的远程配置文件
spring: profiles: active: dev --- #端口配置 server: prot: 8201 #spring配置 spring: profiles: dev application: name: springcould-provider-dept #eureka配置 eureka: client: service-url: defaultZone: http://eureka7001.com:7001/eureka/ --- #端口配置 server: prot: 8202 #spring配置 spring: profiles: test application: name: springcould-provider-dept #eureka配置 eureka: client: service-url: defaultZone: http://eureka7001.com:7001/eureka/
- 将这个文件更新push到远程仓库
- 创建一个新的子model:springcould-config-client-3355
- 导入依赖
<dependencies> <!--web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--config--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> <version>2.1.1.RELEASE</version> </dependency> <!--actuator--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
- 创建配置文件,这里我们需要学习一个新的配置文件:bootstrap.yml,原来我们创建的都是application.yml,那么这两个配置文件有什么区别呢?
- bootstrap.yml:代表系统级别的配置 - application.yml:代表应用级别的配置 - 在原来学习反射的时候,我们学习了类加载器,其中有3个类加载器 - 根类加载器(bootstrap class loader) - 扩展类加载器(extensions class loader) - 系统类加载器(system class loader) - 其中根加载器的优先级别最高 - 类比学习,bootstrap.yml配置文件的优先级应该比application.yml配置文件的优先级高
- 为什么要搞一个系统配置文件呢?原因就是application.yml中的配置可能和远程仓库中的配置冲突,就会造成配置不能正常的使用,而我们使用bootstrap.yml由于优先级别更高,那么最终配置就会按照bootstrap.yml中的配置为准,可以防止本地和远程仓库中的配置冲突问题
- 在spring cloud config中,只有config服务器模块才去连接远程仓库,而config客户端只应该去连接config服务器,所以config客户端的config.uri属性值应该是config服务端的地址(IP+端口)
spring: cloud: config: uri: http://localhost:3344 #连接config服务端
- config客户端除了要配置config.uri之外,还需要配置自己需要加载远程仓库中的哪一个配置文件,按照刚刚直接通过config服务器获取配置文件的URL,我们需要配置name(配置文件名称)、profile(这个配置文件中的哪一个环境下的配置)、label(配置文件所在分支)、uri(config服务端的地址[IP+端口])
spring: cloud: config: uri: http://localhost:3344 #连接config服务端 name: config-client #配置要加载的远程仓库中配置文件的名称,注意:不要后缀 profile: dev #配置获取这个配置文件在哪一种环境下的配置 label: master #配置从哪一个分支获取配置文件
- 编写入口程序
package com.thhh.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ConfigClient_3355 { public static void main(String[] args) { SpringApplication.run(ConfigClient_3355.class,args); } }
- 注意:入口程序并不需要加什么注解,按照正常的spring boot的入口程序写就行了
- 编写一个controller,用来检测config客户端模块是不是能够读取远程的配置文件并作为自己模块配置文件的一部分进行使用
package com.thhh.springcloud.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ConfigController { @Value("${spring.application.name}") private String applicationName; @Value("${eureka.client.service-url.defaultZone}") private String eurekaServer; @Value("${server.port}") private String serverPort; @RequestMapping("/getConfig") public String getConfig(){ return "applicationName = "+this.applicationName+"\n"+ "eurekaServer = "+this.eurekaServer+"\n"+ "serverPort = "+this.serverPort; } }
- 在上面的controller中,我们使用了注解@Value,用于直接向成员属性中注入指定的值,我们又使用了${ }来解析一些的远程配置文件中才配置了的一些配置变量的值,最后通过controller的一个API向外提供输出服务,我们可以直接访问这个API,来检验config客户端是不是读取到了远程仓库中指定配置文件的内容
- 测试
3.小结
- 通过上面的例子我们就实现了一开始学习spring cloud config的时候讲的那一幅图中的架构
- 上图显示的就是我们的所有config客户端连接config服务端,由服务端再去连接远程的仓库;config服务端只需要配置一次,即在提供config服务端功能的微服务中配置上我们的远程仓库地址即可,至于每一个config客户端要使用远程仓库中的哪一个配置文件,由config客户端自己在自己的微服务模块的配置文件中进行配置即可【注意:我们需要配置name(配置文件名称)、profile(这个配置文件中的哪一个环境下的配置)、label(配置文件所在分支)、uri(config服务端的地址[IP+端口])】
- 这样的操作实现了配置与编码的解耦,原来直接将配置写在微服务的配置文件中的做法称为硬编码,一旦要改动就需要找到原微服务模块进行修改,而现在我们只需要在线的在远程仓库中对存储的配置文件进行修改即可,下一次微服务重启读取到的就是最新的配置,而不用再去修改微服务模块