来自阿里的微服务解决方案
一、项目简介Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。
组件 项目地址 项目wiki 适合人群- 基础的分布式思想
- 掌握Spring Boot
- 了解Spring Cloud Netflix
- 分布式中间件
- windows7/10
- JDK1.8
- Maven3.5.4
- IDEA
- Git
Spring Cloud Alibaba BOM 包含了它所使用的所有依赖的版本。
项目的版本号格式为 x.x.x 的形式,其中 x 的数值类型为数字,从 0 开始取值,且不限于 0~9 这个范围。项目处于孵化器阶段时,第一位版本号固定使用 0,即版本号为 0.x.x的格式。
由于 Spring Boot 1 和 Spring Boot 2 在 Actuator 模块的接口和注解有很大的变更,且spring-cloud-commons 从 1.x.x 版本升级到 2.0.0 版本也有较大的变更,因此 Spring CloudAlibaba 采取跟 SpringBoot 版本号一致的版本:
- 1.5.x 版本适用于 Spring Boot 1.5.x
- 2.0.x 版本适用于 Spring Boot 2.0.x
- 2.1.x 版本适用于 Spring Boot 2.1.x
- 2.2.x 版本适用于 Spring Boot 2.2.x
下表展示了 Spring Cloud Alibaba & Spring Cloud & Spring Boot 兼容关系:
The Spring Cloud Alibaba & Spring Cloud & Spring Boot compatibility table
以后我们的项目选择的版本为:
- Spring Boot 2.2.3.RELEASE
- Spring Cloud Hoxton.SR3
- Spring Cloud Alibaba 2.2.0.RELEASE
Spring Cloud Alibaba BOM 包含了它所使用的所有依赖的版本。如果您是 Maven Central用户,请将我们的 BOM 添加到您的 pom.xml 中的
com.alibaba.cloud spring-cloud-alibaba-dependencies 2.2.0.RELEASE pom import
在下面的章节中,假设您使用的是 Spring Cloud Alibaba bom,相关 starter 依赖将不包含版本号。
三、父项目的创建使用父项目能控制所有子项目依赖的全局版本,能有效的去除子项目里面重复的依赖,减少出错的几率。在此,我们将创建一个父 pom,让所有的子模块都继承该父 pom。
3.1 spring-cloud-alibaba-examples 项目的创建spring-cloud-alibaba-examples 将作为我们子项目的最大父 pom 项目!
注意:在使用 IDEA 之前我们假设您已经设置了相应的 JDK 配置和 Maven 配置
3.1.1 使用 IDEA 创建一个 Maven 项目创建一个新的 Maven 项目
选择 Next:
填写下面的相关信息:
Name:spring-cloud-alibaba-examples Location:D:workspacespring-cloud-alibaba-examples(不要随便放) GroupId:com.bjsxt Version:1.0
最后,点击 finish完成创建的过程!
3.1.2 Spring Boot 版本的控制我们采用
打开项目的 pom.xml 文件,添加依赖内容:
org.springframework.boot spring-boot-starter-parent 2.2.3.RELEASE
这样,我们的项目就已经规定了 Spring Boot 的版本为2.2.3.RELEASE 了。
3.1.3 Spring Cloud 版本的控制我们使用依赖管理的方式来添加 Spring Cloud 的版本信息,在
Hoxton.SR3
之后在
3.1.4 Spring Cloud Alibaba 版本的控制org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import
同样,我们使用依赖管理的方式来添加 Spring Cloud Alibaba 的版本信息。在
... 2.2.0.RELEASE ...
之后在
3.1.4 设置为 pom 的版本方式... .... com.alibaba.cloud spring-cloud-alibaba-dependencies ${com-alibaba-cloud.version} pom import
添加项目的打包方式:
pom
这将保证我们的项目是以 pom 打包的。
3.1.5 完整的 pom.xml3.2 项目的打包 3.2.1 删除项目里面多余的文件夹4.0.0 org.springframework.boot spring-boot-starter-parent 2.2.3.RELEASE com.bjsxt spring-cloud-alibaba-examples 1.0 Hoxton.SR3 2.2.0.RELEASE org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import com.alibaba.cloud spring-cloud-alibaba-dependencies ${com-alibaba-cloud.version} pom import
我们的项目仅仅是一个父 pom 文件,因此,项目只需要保留 pom.xml 即可,我们在此可以删除 src 目录。
点击 Delete 即可删除。
使用 Maven 打包我们的项目。
最后在控制台出现:
代表项目打包成功!
我们打开我们 Maven 设置的本地仓库地址,如图所示:
打开 Maven 里面的 settings.xml 文件,找到该标
发现我们本地仓库的地址位于 D 盘的 libjar 文件夹里面:
打开该文件夹:
发现该文件已经存在,证明我们的打包成功了。
Nacos 致力于发现、配置和管理微服务。它提供了一组简单易用的特性集,帮助快速实现动态服务发现、服务配置、服务元数据及流量管理。使用 Nacos 可以更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。
服务(Service)是 Nacos 世界的一等公民。Nacos 支持几乎所有主流类型的“服务”的发现、配置和管理:
- Kubernetes Service.
- gRPC & Dubbo RPC Service.
- Spring Cloud RESTful Service
1.服务发现和服务健康监测 ,支持基于 DNS 和 RPC 的服务发现,支持基于传输层和应用层的监控检查;
2.动态配置服务 ,可以以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置,同时支持版本追踪和一键回滚等功能;
3.动态 DNS 服务 ,动态 DNS 服务支持权重路由,让您更容易地实现中间层负载均衡、更灵活的路由策略、流量控制以及数据中心内网的简单 DNS 解析服务;
4.服务及其元数据管理 ,管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略、服务的 SLA 以及最首要的 metrics 统计数据。
- 服务 (Service)
服务是指一个或一组软件功能(例如特定信息的检索或一组操作的执行),其目的是不同的客户端可以为不同的目的重用(例如通过跨进程的网络调用)。Nacos 支持主流的服务生态,如 Kubernetes Service、gRPC|Dubbo RPC Service 或者 Spring Cloud RESTful Service. - 服务注册中心 (Service Registry)
服务注册中心,它是服务实例及元数据的数据库。服务实例在启动时注册到服务注册表,并在关闭时注销。服务和路由器的客户端查询服务注册表以查找服务的可用实例。服务注册中心可能会调用服务实例的健康检查 API 来验证它是否能够处理请求。 - 服务元数据 (Service metadata)
服务元数据是指包括服务端点(endpoints)、服务标签、服务版本号、服务实例权重、路由规则、安全策略等描述服务的数据 - 服务提供方 (Service Provider)
是指提供可复用和可调用服务的应用方 - 服务消费方 (Service Consumer)
是指会发起对某个服务调用的应用方 - 配置 (Configuration)
在系统开发过程中通常会将一些需要变更的参数、变量等从代码中分离出来独立管理,以独立的配置文件的形式存在。目的是让静态的系统工件或者交付物(如 WAR,JAR 包等)更好地和实际的物理运行环境进行适配。配置管理一般包含在系统部署的过程中,由系统管理员或者运维人员完成这个步骤。配置变更是调整系统运行时的行为的有效手段之一。 - 配置管理 (Configuration Management)
在数据中心中,系统中所有配置的编辑、存储、分发、变更管理、历史版本管理、变更审计等所有与配置相关的活动统称为配置管理。 - 名字服务 (Naming Service)
提供分布式系统中所有对象(Object)、实体(Entity)的“名字”到关联的元数据之间的映射管理服务,例如 ServiceName -> Endpoints Info, Distributed Lock Name -> Lock Owner/Status Info, DNS Domain Name -> IP List, 服务发现和 DNS 就是名字服务的 2 大场景。 - 配置服务 (Configuration Service)
在服务或者应用运行过程中,提供动态配置或者元数据以及配置管理的服务提供者。
使用 Spring Cloud Alibaba Nacos Discovery,可基于 Spring Cloud 的编程模型快速接入 Nacos服务注册功能。
服务发现是微服务架构体系中最关键的组件之一。如果尝试着用手动的方式来给每一个客户端来配置所有服务提供者的服务列表是一件非常困难的事,而且也不利于服务的动态扩缩容。Nacos Discovery 可以帮助您将服务自动注册到 Nacos 服务端并且能够动态感知和刷新某个服务实例的服务列表。除此之外,Nacos Discovery 也将服务实例自身的一些元数据信息-例如 host,port, 健康检查 URL,主页等内容注册到 Nacos。
二、Nacos Server 安装在使用 Nacos 之前我们首先要获取和安装 Nacos。
2.1 Nacos Server 的下载因为 Spring Cloud Alibaba 2.2.0.RELEASE 内置的 Nacos client 版本为 1.1.4,所以我们使用这个版本的 Nacos。Nacos 下载地址:https://github.com/alibaba/nacos/releases
我们找到 1.1.4 版本后点击:
找到相关系统的压缩包,这里面我使用的是 window 系统,所以我们选择
nacos-server-1.1.4.zip 该文件,来点击下载他。
将下载的 nacos-server-1.1.4 复制到我们的开发工具的文件夹里面。(没有的可以新建一个,养成一个良好的习惯)
使用压缩软件解决到当前的文件夹,这里我使用的是 7-zip(其他的压缩软件类似):
解压完成后,进入 Nacos 目录里面:
bin:可执行文件夹目录,包含:启动、停止命令等等
conf:配置文件目录
target:存放 naocs-server.jar
LICENSE:授权信息,Nacos 使用 Apache License Version 2.0 授权
NOTICE:公告信息
进入${Nacos}/conf目录里面,使用文件编辑器打开application.properties 文件,这里面我使用的是 sublime text:
打开后,如下图所示:
Nacos 默认使用嵌入式数据库实现数据的存储,并不方便观察数据存储的基本情况,这里面我们修改为使用 Mysql 数据库做数据的存储,方便我们观察数据的结构。
在配置文件末尾添加如下配置:
spring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://localhost:3306/nacos?characterEncoding=utf8&connectTi meout=1000&socketTimeout=3000&autoReconnect=true db.user=root db.password=123456
注意:
- 上面的 url 地址是我的服务器地址,如果你的 mysql 安装在虚拟机或云服务器上面,就填写真实的地址。
- db.user 用户名
- db.password 密码
提示:Nacos 建议使用 5.7 以上的 Mysql 数据库,版本较低可能存储兼容性问题 我使用的 Mysql 数据库版本为 5.7
打开${Nacos}/conf/文件夹:
其中nacos-mysql.sql就是 nacos 提供给我们的 sql 语句。
新建数据库:
新建 Nacos 的的数据库:
点击确定完成创建。
导入sql语句:
选择我们 nacos-mysql.sql文件:
点击开始,完成导入:
已经成功导入,包含如下的表:
具体表的细节和设计,我将在源码分析的阶段讲解。
上面工作都完成后,现在我们来启动一个单机版的 Nacos 服务器。
进入到${Nacos}/bin 目录里面:
双击 startup.cmd 文件,完成 nacos 的启动。
直到日志出现:
代表我们已经成功的启动了一个 Nacos 单机版的实例。
在浏览器里面输入:
http://localhost:8848/nacos ,即可访问启动 Nacos 实例。
Nacos 默认用户名和密码都是 nacos。
输入正确的用户名和密码提交后,出现 Nacos 的控制台界面。
至此,Nacos Server 已经安装成功。
我们将使用搭建所示的测试案例。
我们将为 Nacos 创建一个单独项目,方便我们来学习和管理 nacos 的相关功能。
使用 IDEA 创建一个 Maven 模块:
点击 next:
Name:nacos-examples
其他项将会自动的填充进去。
点击 Finish 完成创建。
修改 nacos-examples 里面的 pom.xml 文件,在此我们引入:
- spring-boot-starter-web (spring-boot-web 开启的最基础的依赖)
- spring-cloud-alibaba-nacos-discovery(nacos 做服务发现的最基础的依赖)
在
org.springframework.boot spring-boot-starter-web com.alibaba.cloud spring-cloud-alibaba-nacos-discovery
修改 nacos-examples 项目的打包方式:
pom
最后,完整的 pom.xml 文件如下所示:
3.2 创建服务的提供者 providerspring-cloud-alibaba-examples com.bjsxt 1.0 4.0.0 nacos-examples pom org.springframework.boot spring-boot-starter-web com.alibaba.cloud spring-cloud-alibaba-nacos-discovery
服务提供者将为以后的服务消费者提供一些接口的供远程调用。
使用 IDEA 为 nacos-examples 创建一个子模块:
将 Next 进入下一步操作:
注意:我们的 parent 必须选择为 nacos-examples。
Name:provider(服务的提供者)
其他的项将自动的填充,不需要我们修改。
Provider 的依赖分析:
我们的 provider 已经自动的从 nacos-exmaples 里面把这 2 个依赖继承过来了。
服务消费者将远程调用服务提供者提供的接口。
使用 IDEA 为 nacos-examples 创建一个子模块:
将 Next 进入下一步操作:
注意:我们的 parent 必须选择为 nacos-examples。
Name:consumer(服务的提供者)
其他的项将自动的填充,不需要我们修改。
Consumer 的依赖分析:
我们的 consumer 已经自动的从 nacos-exmaples 里面把这 2 个依赖继承过来了。
至此,我们项目的骨架已经搭建完成。如下图所示:
Provider 现在还是一个空的项目,里面没有任何的数据接口。
4.1.1 添加一个 application.yml 配置文件我们给 provider 添加一个配置文件:
文件的名称为:
完成创建后,IDEA 能自动的识别该 yml 文件。
编辑该配置文件,添加如下的配置:
server: port: 8080 spring: application: name: provider-service cloud: # nacos注册中心地址的配置法 nacos: discovery: server-addr: localhost:8848
配置说明:
- server.port provider 服务端口为 8001 ;
- spring.application.name 服务名称为 provider-service;
- spring.cloud.nacos.server-addr ,指定 Nacos 注册中心的地址;
Provider 还没有启动类,我们需要给他添加一个。
名称为:com.bjsxt.ProviderApplication
com.bjsxt 为包名,ProviderApplicaton 为类的名称,创建完成后,自动的出现:
在该类里面添加如下的代码:
@SpringBootApplication // 标记为 SpringBoot 的应用
@EnableDiscoveryClient // 启用服务发现和注册的功能
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class,args) ;
}
}
4.1.3 添加一个 API 接口
提供者通过提供 API 接口供服务提供者调用。
在 provider 里面创建一个类:
名称为 controller.EchoController
成功后,如下图所示:
添加一个接口:
@RestController
public class EchoController {
@GetMapping("/echo/{message}")
public ResponseEntity echo(@PathVariable("message")
String message){
return ResponseEntity.ok(String.format("hello,%s",message)) ;
}
}
该接口将会对访问的人输入一个 hello,xxx。
4.1.4 启动 provider 测试现在我们的 provider 已经准备就绪,启动看能否注册到 Nacos 上面 。
发现 provider 已经启动成功了。
打开 Nacos 页面观察 provider 是否上
服务的提供者已经成功的上线了。
Consumer 现在还是一个空的项目,里面没有任何的数据接口,也没有对服务的提供者进行调用。
4.2.1 添加一个 application.yml 配置文件我们给 consumer 添加一个配置文件
名称为:application.yml
IDEA 能自动的识别该配置文件的:
编辑该文件,给该文件添加如下的配置信息:
server: port: 8090 spring: application: name: consumer-service cloud: nacos: discovery: server-addr: localhost:88484.2.2 添加一个启动类
Consumer 现在还没有任何的启动类,我们需要给他添加一个。
名称为:com.bjsxt.ConsumerApplication
创建成功后,如下图所示:
在该类里面添加如下代码:
@SpringBootApplication // 标记为 SpringBoot 的应用
@EnableDiscoveryClient // 开启服务的发现和注册功能
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class,args) ;
}
}
4.2.3 服务发现的测试
继续改造启动类,在里面添加如下代码:
@Autowired
private DiscoveryClient discoveryClient ;// 快速服务的发现
@GetMapping("/discovery/{serviceName}")
public ResponseEntity> discovery(@PathVariable("serviceName")
String serviceName){
List instances =
discoveryClient.getInstances(serviceName);
if(instances==null || instances.isEmpty()){
return ResponseEntity.notFound().build() ;
}
List services = new ArrayList<>(instances.size());
instances.forEach(instance->{
services.add(instance.getHost()+":"+instance.getPort());
});
return ResponseEntity.ok(services) ;
}
因为我们在启动类里面添加了接口,所以要必须添加@RestController 该注解来标记该类:
最后,我们启动 consumer-service 项目:
观察 consumer-service 是否成功的注册到了 Nacos 上面:
Consumer-service 已经成功了上线了。
在浏览器输入:
http://localhost:8090/discovery/provider-service
其中:provider-service 代表服务的名称
服务器给我们响应:
代表服务已经发现成功。
输入一个不存在的服务名称:
http://localhost:8090/discovery/provider
服务器给我们响应:
代表,该服务还没有服务的提供者。
在 consumer,我们调用 provider 里面的 echo 接口
继续改造我们的启动类,注册一个 RestTemplate 对象:
@Bean
public RestTemplate restTemplate(){
return new RestTemplate() ;
}
调用测试:
@Autowired
private RestTemplate restTemplate ;
@GetMapping("/rpcv1/{message}")
public ResponseEntity rpcV1(@PathVariable("message") String message){
ResponseEntity responseEntity = restTemplate.getForEntity(
"http://localhost:8081/echo/{message}",
String.class,
message
);
if(responseEntity.getStatusCode()==HttpStatus.OK){
return ResponseEntity.ok(String.format("远程调用成功,结果为%s",responseEntity.getBody())) ;
}
return ResponseEntity.badRequest().body("远程调用失败") ;
}
@GetMapping("/rpcv2/{message}")
public ResponseEntity rpcV2(@PathVariable("message") String message){
List instances =
discoveryClient.getInstances("nacos-provider");
if(instances==null || instances.isEmpty()){
return ResponseEntity.badRequest().body("当前服务没有服务的提供者") ;
}
ServiceInstance serviceInstance = instances.get(0);
String instance =
serviceInstance.getHost()+":"+serviceInstance.getPort() ;
ResponseEntity responseEntity = restTemplate.getForEntity(
String.format("http://%s/echo/{message}",instance),
String.class,
message
);
if(responseEntity.getStatusCode()==HttpStatus.OK){
return ResponseEntity.ok(String.format("远程调用成功,结果为%s",responseEntity.getBody())) ;
}
return ResponseEntity.badRequest().body("远程调用失败") ;
}
@GetMapping("/rpcv3/{message}")
public ResponseEntity rpcV3(@PathVariable("message") String message){
List instances = discoveryClient.getInstances("nacos-provider");
if(instances==null || instances.isEmpty()){
return ResponseEntity.badRequest().body("当前服务没有服务的提供者") ;
}
ServiceInstance serviceInstance = loadbalance(instances);
System.out.println(serviceInstance);
String instance =
serviceInstance.getHost()+":"+serviceInstance.getPort() ;
ResponseEntity responseEntity = restTemplate.getForEntity(
String.format("http://%s/echo/{message}",instance),
String.class,
message
);
if(responseEntity.getStatusCode()==HttpStatus.OK){
return ResponseEntity.ok(String.format("远程调用成功,结果为%s",responseEntity.getBody())) ;
}
return ResponseEntity.badRequest().body("远程调用失败") ;
}
其中,loadBalance 的实现逻辑为:
private ServiceInstance loadbalance(Listinstances) { Random random = new Random(System.currentTimeMillis()); return instances.get(random.nextInt(instances.size())) ; }
重启 Consummer-service:
在浏览器里面输入:
http://localhost:8090/rpc/world
服务器给我们相应的数据为:
远程调用已经成功!
当服务压力突然变大时,我们需要通过对服务进行弹性伸缩和动态的扩容,让服务展示更强的并发能力和容错能力。
5.1 修改服务提供者的数据接口修改服务提供者的接口,可以让我们很清晰的看到,我们当前调用的是那一台服务提供者。
让我们来修改 provider 里面 EchoController 这个类
代码如下:
@RestController
public class EchoController {
@Value("${server.port}")
private Integer port ;
@GetMapping("/echo/{message}")
public ResponseEntity echo(@PathVariable("message") String
message){
return ResponseEntity.ok(String.format("hello,%s,我是服务提供者:%s",message,port)) ;
}
}
因为我们在同一台机器上启动多个服务提供者,那服务提供者的端口肯定不相同,我们在此使用 port 作为服务提供者的唯一标示。
@Value : 从 env 里面注入这个值
先停止所有的服务:
在启动一个服务的提供者:
启动成功后:
启动其他 1 个:
进入编辑页面:
2 个操作:
Name:不能重复,这里我修改为 ProviderApplication-2
Program arguments:--server.port=8081这句话的意思是,在启动该服务时,添加一个变量: server.port=8081,类似我们使用这样的命令启动:
java -jar xxx.jar --server.port=8081
--server.port该 值 将 会 被 添 加 到 spring 的 env 里 面 , 并 且 该 方 式 的 优 先 级 高 于application.yml 里面的配置值。所以,系统会使用该 port 来启动服务。
修改完毕后,点击 ok。
现在启动我们的复制的 ProviderApplicaton-2:
观察 Nacos 里面的数据:
服务:provider-service 已经有 2 个实例了,点击详情:
可以手动的下线该服务。
修改 consumer 里面的 ConsumerApplication ,在里面的末尾添加如下的代码:
@Autowired
private LoadBalancerClient loadBalancerClient ;
@GetMapping("/choose/{serviceName}")
public ResponseEntity choose(@PathVariable("serviceName") String serviceName){
ServiceInstance instance = loadBalancerClient.choose(serviceName);
System.out.println(String.format("本次选择的实例
为:%s:%s",instance.getHost(),instance.getPort()));
return ResponseEntity.ok(instance.getHost()+":"+instance.getPort()) ;
}
其中:
- LoadBalancerClient :Ribbon 提供给我们最外层的接口,使用它我们可以很轻易的实现负载均衡。
- LoadBalancerClient.choose(serviceName):通过给定的服务名称,Ribbon 底层通过负载均衡的算法得到一个可以进行远程的实例。
现在,启动 Consumer 进行测试:
在浏览器里面输入:
http://localhost:8090/choose/provider-service
得到:
刷新页面:
并且后台输出:
发现负载均衡已经完成。
在之前,我们在 consumer 使用 RestTemplate 调用 provider 时,手动实现了负载均衡,url的拼接:
代码相当的冗余。现在,我们使用 Ribbon 的方式来实现:
在注入 RestTemplate 的方法上添加注解:
远程调用的代码变为:
@GetMapping("/rpc/ribbon/{message}")
public ResponseEntity rpcByRibbon(@PathVariable("message") String
message){
ResponseEntity responseEntity =
restTemplate.getForEntity("http://provider-service/echo/" + message,
String.class);
if(responseEntity.getStatusCode()==HttpStatus.OK){
return ResponseEntity.ok("调用成功,provider-service 相应给我们的数据为:"+responseEntity.getBody()) ;
}
return ResponseEntity.badRequest().body("调用失败,provider-service 的相应码为:"+responseEntity.getStatusCode()) ;
}
重启 consumer 测试:
在浏览器里面输入:
http://localhost:8090/rpc/ribbon/{message}
刷新测试:
负载均衡已经完成了。
Nacos Discovery 内部提供了一个 Endpoint, 对应的 endpoint id 为 nacos-discovery。我们通过该 Endpoint,能获取到:
- 当前服务有哪些服务订阅者 ;
- 当前应用 Nacos 的基础配置信息 ;
假设我们想看服务提供者(provider)有那些订阅者,以及 Nacos 的基础配置信息。
我们就需要给 provider 项目的 pom.xml 文件里面添加:
6.2 修改配置文件org.springframework.boot spring-boot-starter-actuator
Endpoint 本身对外界隐藏显示,我们需要在配置里面开启对 Endponit 的显示支持。
修改 application.yml 配置文件,在里面添加如下的配置:
management: endpoints: web: exposure: include: "*"
说明:
- exposure.include:对外界保留那些 Endpoint,若是所有则使用*;
重启项目,浏览器访问:
http://localhost:8081/actuator/nacos-discovery
效果为:
使用 Spring Cloud Alibaba Nacos Config,可基于 Spring Cloud 的编程模型快速接入 Nacos 配置管理功能。
上一节 Spring Cloud Alibaba Nacos 注册中心记录了 Nacos 作为注册中心的使用方式,这节继续记录下Nacos作为配置中心的使用方式。本节使用的Spring Cloud版本为Hoxton.SR3,Spring Cloud Alibaba 版本为 2.2.0.RELEASE,Spring Boot 版本为 2.2.3.RELEASE。
二、项目的搭建
我们将在我们 nacos-examples 的基础上,搭建一个 config-client,用来 nacos 配置中心的案例测试。
使用 IDEA 创建一个 Maven 模块:
选择 Maven:
点击下一步:
Parent:选择 nacos-examples
Name:config-client
其他的项,保持默认。
点击 FINISH 完成创建的过程:
我们的项目继承自 nacos-examples,它里面已经包含 2 个基本的依赖:
- 服务注册和发现:spring-cloud-alibaba-nacos-discovery 这个是微服务里面必不可缺的组件
- Web 开发相关:spring-boot-starter-web 开发 web 项目最基础的依赖现在,我们在里面添加今天我们要学习的配置获取的组件:
spring-cloud-alibaba-nacos-config
编辑 config-client 里面的 pom.xml 文件,添加以下的内容:
com.alibaba.cloud spring-cloud-alibaba-nacos-config
在添加一个 mavne 的打包插件:
org.springframework.boot spring-boot-maven-plugin
查看项目所有的依赖:
现在,项目里面已经包含上面的 3 个依赖了。
nacos-examples com.bjsxt 1.0 4.0.0 config-client com.alibaba.cloud spring-cloud-alibaba-nacos-config org.springframework.boot spring-boot-maven-plugin
至此,项目的搭建完成了。
三、在 nacos-server 里面添加配置相关的工作图,如图:
Nacos-client 会从 Nacos-Server 里面获取配置文件,首先,Nacos-Server 里面需要有配置文件才能获取。
新建如下所示的配置信息:
打开 Nacos 的管理页面:
现在我们看见,里面还没有任何的配置信息。
点击:
让我们来新建一个配置项:
填写的表单如下:
点击发布,完成配置文件的发表任务:
返回后,配置信息已经发布成功:
我们将演示在 config-client 里面获取上面我们写的 2 个配置信
4.1 添加一个配置文件
文件名称为:
注意:不是 application.yml ,bootstrap.yml 比 application 有更高的优先级。
Idea 能自动的识别该文件的格式:
编辑该文件,添加以下内容:
server: port: 8070 spring: cloud: nacos: discovery: server-addr: localhost:8848 config: # 指定配置中心的地址和配置中心使用的数据格式 server-addr: localhost:8848 file-extension: properties application: name: config-clien
配置说明:
server.port: 服务的运行端口
名称为:com.bjsxt.ConfigClientApplication
编辑该类:
@SpringBootApplication
@EnableDiscoveryClient
@RefreshScope
@RestController
public class ConfigClientApplication {
@Value("${user.name}")
private String userName ;
@Value("${user.age}")
private Integer userAge ;
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class,args) ;
}
@GetMapping("/user/info")
public ResponseEntity getUser(){
return ResponseEntity.ok(
String.format("从配置中心获取的信息为:user:%s,
age:%s",userName,userAge)) ;
}
}
说明:
@RefreshScope:代表配置文件是可以被刷新的
@Value:从 env 里面获取配置信息
在浏览器里面输入:
http://localhost:8070/user/info
效果已经完成了。
nacos 配置中心通过 namespace、dataId 和 group 来唯一确定一条配置。
- Namespace:即命名空间。默认的命名空间为 public,我们可以在 Nacos 控制台中新建命名空间;
- dataId:即配置文件名称
- Group:即配置分组,默认为 DEFAULT_GROUP,可以通过 spring.cloud.nacos.config.group配置。
其中:dataId 是最关键的配置字段:格式如下:
${prefix} - ${spring.profiles.active} .${file-extension}
说明:
- prefix 默 认 为 spring.application.name的 值 , 也 可 以 通 过 配 置 项spring.cloud.nacos.config.prefix来配置;
- spring.profiles.active即为当前环境对应的 profile。注意,当 spring.profiles.active为空时,对应的连接符-也将不存在,dataId 的拼接格式变成${prefix}.${file-extension};
- file-extension 为 配 置 内 容 的 数 据 格 式 , 可 以 通 过 配 置 项spring.cloud.nacos.config.file-extension来配置。
这就是上面我们为什么能获得到配置的原因了。
六、配置划分实战
Nacos 配置中心的 namespace、dataId 和 group 可以方便灵活地划分配置。比如,我们现在有一个项目需要开发,项目名称为 bjsxt,项目开发人员分为两个组:GROUP_A 和 GROUP_B,
项目分为三个环境:开发环境 dev、测试环境 test 和生产环境 prod。
Bjsxt->GRUOR_A->dev
点击新建命令空间:
填写以下的内容:
点击确定,完成创建。
完成后,如图所示:
新建完成后:我们看见它自动帮我们生产了一个 ID:
8defab18-df88-49e5-b13e-526f89da87ad
记录该 ID 值
6.2 在 Nacos 新建
切换完成后,点击 +:
填写以上的信息。点击发布:
完成后:
已经完成创建。
修改 config-client 里的 bootstrap.yml 文件:
server:
port: 8070
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
config: # 指定配置中心的地址和配置中心使用的数据格式
server-addr: localhost:8848
file-extension: yml #properties
group: GROUP_A # 获取 GROUP_A 里面的配置
namespace: 8defab18-df88-49e5-b13e-526f89da87ad # 命名空间,注意写 id的值不是name
# prefix: ${spring.application.name} # 前缀,默认为应用的名称,不需要修改
application:
name: config-client
profiles:
active: dev # 使用的 dev 环境的配
6.4 重启 config-client 测试
浏览器访问:
http://localhost:8070/user/info
得到:
配置信息已经获取成功。
Nacos 中,修改配置点击发布后会创建一个对应的历史版本快照,我们可以在 Nacos 控制台的历史版本列表中找到这些快照。
7.1 动态刷新
该注解,可以刷新配置。故无需启动就能看见最新的配置信息。
修改 user.name ,user.age:
点击发布。
出现对比页面:
点击确认发布:
然后点击返回。
可以看见修改的日期。
将配置信息回滚为之前的版本:
根据修改时间,我们将 12:38:53 的数据回滚为 12:25:12 的数据:
已经自动的展示回滚的内容了,点击回滚配置:
点击确认,完成回滚:
再次测试:
浏览器输入:
http://localhost:8070/user/info
已经回滚成功了:
除了通过上面的方式指定一个唯一配置外,我们还可以同时获取多个配置文件的内容。
8.1 修改 config-client 里面的配置文件server:
port: 8070
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
config:
extension-configs: # 多个配置
- dataId: test-a.yml
group: DEFAULT_GROUP
refresh: true
- dataId: test-b.yml
group: DEFAULT_GROUP
refresh: false
# 指定配置中心的地址和配置中心使用的数据格式
# server-addr: localhost:8848
# file-extension: yml #properties
# group: GROUP_A # 获取 GROUP_A 里面的配置
# namespace: 8defab18-df88-49e5-b13e-526f89da87ad # 命名空间,写 id 的值
## prefix: ${spring.application.name} # 前缀,默认为应用的名称,不需要修改
application:
name: config-client
profiles:
active: dev # 使用的 dev 环境的配置
说明:
- spring.cloud.nacos.config.extension-configs[n].dataId,指定多个配置的 dataId,必须包含文件格式,支持 properties、yaml 或 yml;
- spring.cloud.nacos.config.extension-configs[n].group,指定分组;
- spring.cloud.nacos.config.extension-configs[n].refresh,是否支持刷新。
上 面 的 配 置 中 , 我 们 分 别 从DEFAULT_GROUP 中 获 取 了 config-client-a.yml 和config-client-b.yml配置内容,并且 config-client-a.yml支持刷新,config-client-b.yml不支持刷新。
注意:没有 namespace 的配置,言外之意就是 Nacos 目前还不支持多个配置指定不同的命名空间。
8.2 在 Nacos 里面完成这 2 个配置文件的创建config-client-a.yml:
切换 namespace:
点击 + 完成创建:
点击发布。
config-client-b.yml
完成后:
重启 config-client,测试:
浏览器访问:



