本节配套案例代码:Gitee仓库、Github仓库
所有博客文件目录索引:博客目录索引(持续更新)
学习视频:动力节点最新SpringCloud视频教程|最适合自学的springcloud+springcloudAlibaba
PS:本章节中部分图片是直接引用学习课程课件,如有侵权,请联系删除。
springcloud的版本说明:
当前项目环境版本:springboot 2.3.12.RELEASE
、springcloud alibaba 2.2.7.RELEASE
nacos 中文网站
介绍:Nacos不仅仅提供注册中心,还提供了配置中心,在配置中心中我们可以对不同组的服务来进行隔离能够更有效的进行开发,同时还具备登录的一个功能,其中的配置中心还提供了数据持久化。【注册中心不需要数据库、配置中心需要】
Nacos是阿里巴巴新推出的开源项目,致力于发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,快速实现动态服务发现、服务配置、服务元数据及流量管理。
Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。
Nacos 支持如下核心特性:
1、服务发现: 支持 DNS 与 RPC 服务发现,也提供原生 SDK 、OpenAPI 等多种服务注册方式和 DNS、HTTP 与 API 等多种服务发现方式。
2、服务健康监测: Nacos 提供对服务的实时的健康检查,阻止向不健康的主机或服务实例发送请求。
3、动态配置服务: Nacos 提供配置统一管理功能,能够帮助我们将配置以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置。
4、动态 DNS 服务: Nacos 支持动态 DNS 服务权重路由,能够让我们很容易地实现中间层负载均衡、更灵活的路由策略、流量控制以及数据中心内网的简单 DNS 解析服务。
5、服务及其元数据管理: Nacos 支持从微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略、服务的 SLA 以及最首要的 metrics 统计数据。
目前市面上的注册中心如下:
1、Eureka(原生,2.0遇到瓶颈,停止维护)
2、Zookeeper(支持,专业的独立产品。例如:dubbo)
3、Consul(原生,GO语言开发)
4、Nacos(阿里巴巴)
Nacos = Spring Cloud Eureka + Spring Cloud Config
Nacos与eureka的区别:
共同点:
不同点:
画图举例(直接引用的课件图):
很明显的两个区别:eureka注册中心没有登录,对于不同服务并没有分组
在nacos中不仅仅会有不同的命名空间,在一个空间中还可以进行分组划分隔离:
nacos 下载地址
1、下载安装包
选择zip下载即可:
2、修改bin/start.up可执行文件中的配置
我们之后是通过bin目录下的startup.cmd来启动nacos服务,在2.0.3版本中,cmd里是默认设置以集群模式来进行启动的,所以若是我们只是单机启动一个就会报错,那么如何修改模式为单机呢?
set MODE="standalone"
3、mysql中创建nacos数据库以及导入表
nacos中配备有用户登录以及配置中心的功能,所以一些数据内容需要进行持久化存储,所以的话我们需要搭配mysql来进行使用。
MySQL版本:5.7最佳,8.0暂未试过。
首先我们找到nacos提供给我们的sql文件:
接着在数据库中创建【nacos】,接着导入sql即可,最终效果如下:
此时默认用户表中包含一条记录我们之后可以来用其进行登录:
用户名:nacos
密码:nacos # 密码是采用bcrypt加盐加密的
4、修改nacos的配置文件,开启mysql的配置项
进入到conf文件中,来编辑properties配置文件,将下面的五项连接数据库的内容取消注释:
5、启动Nacos并登录
进入到bin目录中,执行命令:
start startup.cmd
看到successful字样说明我们已经启动成功!
来访问下管理页面把:http://192.168.10.37:8848/nacos/index.html#/login
使用用户密码nacos、nacos来登录,我们可以在结点列表中查看到自己的节点ip地址:
服务(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 -> LockOwner/Status Info, DNS Domain Name -> IP List, 服务发现和 DNS 就是名字服务的2 大场景。
配置服务 (Configuration Service)
在服务或者应用运行过程中,提供动态配置或者元数据以及配置管理的服务提供者。
目标:搭建两个服务并进行注册到nacos中,主要是进行命名空间以及分组的熟悉。
首先来搭建工程环境,这里我们使用阿里云的服务地址来进行快速创建springboot项目:
地址:https://start.aliyun.com
https://start.aliyun.com
都选择使用nacos的注册发现依赖以及web模块:
<properties>
<java.version>1.8java.version>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<spring-boot.version>2.3.12.RELEASEspring-boot.version>
<spring-cloud-alibaba.version>2.2.7.RELEASEspring-cloud-alibaba.version>
properties>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>${spring-boot.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-dependenciesartifactId>
<version>${spring-cloud-alibaba.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
01-nacos-client-a
1、开启服务发现:在启动器上
@EnableDiscoveryClient //开启服务发现
2、编写配置文件:application.yaml
server:
port: 8081
spring:
application:
name: nacos-client-a # 服务名
cloud:
nacos: # 如果不指定命名空间会默认注册到public里面去 如果没有指定分组 会注册到DEFAULT_GROUP
server-addr: localhost:8848 # 指定服务注册地址
username: nacos
password: nacos
discovery:
# namespace: 477245fa-d5e1-47e0-9580-4a8e268c3f58 # 若是不指定,默认就是public
# group: A_GROUP # 若是不指定,默认是DEFAULT_GROUP
service: nacos-client-a # 默认使用的是spring.application.name,这里可以进行指定
02-nacos-client-b
与上述相同,同样也是开启注册发现以及编写配置文件,这里就贴下配置文件:
server:
port: 8082
spring:
application:
name: nacos-client-b # 服务名
cloud:
nacos: # 如果不指定命名空间会默认注册到public里面去 如果没有指定分组 会注册到DEFAULT_GROUP
server-addr: localhost:8848 # 指定服务注册地址
username: nacos
password: nacos
discovery:
namespace: 477245fa-d5e1-47e0-9580-4a8e268c3f58 # 若是不指定,默认就是public
group: B_GROUP # 若是不指定,默认是DEFAULT_GROUP
service: nacos-client-b # 默认使用的是spring.application.name,这里可以进行指定
其中的namespace的一长串id是我们创建的命名空间的值,我们在nacos控制台来创建下面的nacos-demo命名空间即可,旁边则是ID:
接下来我们来启动项目,并进行nacos控制台进行查看:
首先是client-a
,在该工程模块中并没有指明命名空间和组名,所以就会默认public命名空间以及DEFAULT_GROUP组。
接下来是client-b
:果然在我们之前创建的nacos-demo命名空间中进行了创建
目标:创建gateway网关,通过使用动态路由去访问网关来进行路由转发到client-a服务去远程调用client-b服务。
要想nacos-client-a服务能够去远程调用client-b的服务,那么首先b就需要对外暴露一个接口:
package com.changlu.nacosclientb.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
/**
* @Description:
* @Author: changlu
* @Date: 9:15 PM
*/
@RestController
public class MemberController {
@GetMapping("/info")
public String info() {
String info = "client-b:" + UUID.randomUUID().toString();
return info;
}
}
接着就开始``client-a`模块的集成feign:
集成feign的话,那么就需要指定springcloud的版本依赖以及引入cloud-feign的组件依赖:
<properties>
<spring-cloud.version>Hoxton.SR12spring-cloud.version>
properties>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
1、接着我们在启动器上添加开启feign包扫描注解:
com.changlu.nacosclienta.NacosClientAApplication
:
@EnableFeignClients //开启feign包扫描
2、编写指定的feign接口
com.changlu.nacosclienta.feign.MemberFeign
:
package com.changlu.nacosclienta.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
/**
* @Description:
* @Author: changlu
* @Date: 9:17 PM
*/
@FeignClient(value = "nacos-client-b")
public interface MemberFeign {
@GetMapping("/info")
String info();
}
3、最后就是在client-a服务中也编写一个服务,该服务会去远程调用服务b
package com.changlu.nacosclienta.controller;
import com.changlu.nacosclienta.feign.MemberFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Description:
* @Author: changlu
* @Date: 9:19 PM
*/
@RestController
public class TestController {
@Autowired
private MemberFeign memberFeign;
@GetMapping("/testClientA")
public String testClientA() {
String info = memberFeign.info();
return info;
}
}
此时client-a中的指定命名空间以及组名都已经改为与client-b一致:
Gateway的底层是基于netty的,所以我们无需引入web模块,只需要引入一个nacos的注册发现以及一个gateway组件依赖即可:
<properties>
<java.version>1.8java.version>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<spring-boot.version>2.3.12.RELEASEspring-boot.version>
<spring-cloud-alibaba.version>2.2.7.RELEASEspring-cloud-alibaba.version>
<spring-cloud.version>Hoxton.SR12spring-cloud.version>
properties>
<dependencies>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-gatewayartifactId>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>${spring-boot.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-dependenciesartifactId>
<version>${spring-cloud-alibaba.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
1、application.yaml
:在yaml配置中来打开动态路由以及注册服务的一些配置:
server:
port: 81
spring:
application:
name: gateway-service # 服务名
cloud:
nacos: # 如果不指定命名空间会默认注册到public里面去 如果没有指定分组 会注册到DEFAULT_GROUP
server-addr: localhost:8848 # 指定服务注册地址
username: nacos
password: nacos
discovery:
namespace: 477245fa-d5e1-47e0-9580-4a8e268c3f58 # 若是不指定,默认就是public
group: B_GROUP # 若是不指定,默认是DEFAULT_GROUP
service: gateway-service # 默认使用的是spring.application.name,这里可以进行指定
gateway: # 网关配置
discovery:
locator:
enabled: true # 开启动态路由
lower-case-service-id: true
2、在启动器上添加一个开启服务注册的注解:
@EnableDiscoveryClient
此刻我们的feign以及gateway组件就已经集成完毕了!
额外说明:对于在nacos中feign的远程调用只允许调用相同命名空间中的相同组里的某个服务!否则就会报异常找不到该服务,已进行过测试。
准备工作:开启nacos服务器,以及启动gateway网关以及client-a、client-b服务。
首先来直接调用client-a的接口试试:http://localhost:8081/testClientA
没问题之后,我们来进行调用网关的的动态路由接口,看能够直接路由到client-a
服务中去:
到此,测试完成!
思路:nacos的集群服务也是比较简单的,在同一台机子中修改不同的端口号以及在cluster.conf配置文件中修改指定的ip以及端口,然后同时进行启动即可完成nacos的集群服务搭建。
为了方便三个服务同时来进行启动,我们准备了三个nacos服务:
分别是:8081、8083、8085端口
三个nacos中分别去修改application.properties文件以及cluster.conf配置文件:
application.properties
:
cluster.conf
:
#2022-07-30T22:23:32.909
192.168.10.37:8081
192.168.10.37:8083
192.168.10.37:8085
ok,接下来我们去启动三个nacos服务,也就是集群,在三个文件的bin目录下执行:``start startup.cmd`
我们来启动client-a、client-b以及gateway,三个服务的注册地址都填写8081端口,之后我们来打开其他nacos服务的管理页面看是否能够进行同步。
ok,此时我们去到管理界面来查看一下:
成功!
原本我们是写在每个配置文件中的,若是我们要修改配置文件,那么就需要去重新打包然后部署,对于在微服务时代,可能会有大量的重复实例,难道要重新去一个个重启部署吗?
在nacos配置中心中我们可以根据不同的分组来进行管理我们的配置文件,并且对应的服务也能够进行动态去读取配置文件的最新内容,在nacos配置中心里其配置是进行持久化存储的,其是存储在mysql数据库当中。
注意了,配置格式一定要选择yaml,因为之后我们配置文件配置的文件类型就是yaml,否则会一直读取不到的!
接着点击发布即可:
引入依赖:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
1、开启服务注册注解:
@EnableDiscoveryClient
2、配置类User:
package com.changlu.nacosconfig.config;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @Description:
* @Author: changlu
* @Date: 10:58 PM
*/
@Component
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@Value("${user.username}")
private String username;
@Value("${user.age}")
private Integer age;
@Value("${user.sex}")
private String sex;
@Value("${user.hobby}")
private String hobby;
@Value("${user.height}")
private Integer height;
}
3、添加一个控制器,在控制器中会去返回读取配置信息的内容
package com.changlu.nacosconfig.controller;
import com.changlu.nacosconfig.config.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Description:
* @Author: changlu
* @Date: 11:06 PM
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private User user;
@GetMapping("/info")
public String getUserInfo() {
System.out.println(user);
String res = this.user.toString();
//注意:添加了@RefreshScope注解不能在mvc的方法中直接返回,因为该user是代理类,进行序列化会进行报错!
return res;
}
}
4、关键的来了,配置文件的参数设置
bootstrap.yml:该配置会先于application.yaml读取
server:
port: 8081
spring:
application:
name: nacos-config
profiles:
active: dev
cloud:
nacos:
config:
server-addr: localhost:8848
# 指定命名空间和组名(默认是去public空间及DEFAULT_GROUP组中去找)
# namespace: 477245fa-d5e1-47e0-9580-4a8e268c3f58 # 若是不指定,默认就是public
# group: B_GROUP # 若是不指定,默认是DEFAULT_GROUP
# 关键两个读取配置的信息
# prefix: nacos-config # 配置文件的前缀
file-extension: yml # 文件类型
对于配置文件的名字会如下进行搜索:当前是在public空间
、`DEFAULT_GROUP组``
注意:一旦我们指定指定的命名空间与组时,那么就会去该组中查找是否有该配置,若是没有项目会在启动过程中就会报错!
我尝试了下,报错内容如下:
还是依据上面的配置来进行启动,接着去访问接口:http://localhost:8081/user/info
成功读取到配置!
注意:添加了@RefreshScope注解不能在mvc的方法中直接返回,因为该user是代理类,进行序列化会进行报错!
方式一:读取某个属性使用@Value注解,并在对应的配置类上添加@RefreshScope
import org.springframework.cloud.context.config.annotation.RefreshScope;
@RefreshScope //刷新配置注解
public class Config {
@Value("${config.name}")
private String name;
@Value("${config.type}")
private String type;
}
方式二:直接使用@ConfigurationProperties 读取配置,如下
@ConfigurationProperties(prefix = "config")
public class Config {
private String name;
private String type;
}
下面图例来自:Nacos实现配置管理及集群搭建,觉得讲的很清晰直接拿来了,如有侵权,联系我删除。
在没加入 Nacos 配置之前,获取配置是这样:
加入 Nacos 配置,它去读取远程nacos的配置文件是在 application.yml 之前的:
所以我们此时不能够在application.yml中来去配置远程nacos的配置中心地址,应当在更高优先级的bootstrap.yml文件中来进行配置:
这就是我们为什么要再bootstrap配置文件中进行书写配置的原因了!
在nacos中提供了多环境读取配置、共享多组配置变量以及扩展多组配置文件。
spring.application.active
变量来进行指定即可。shared-configs
配置参数,你可以来配置多条相同命名空间不同组的配置文件。extension-configs
配置参数,你可以来配置多条相同命名空间不同组的配置文件。下面就来尝试下:
准备好我们的配置类以及一个控制器来进行输出配置类信息:
package com.changlu.nacosconfig.config;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @Description:
* @Author: changlu
* @Date: 10:12 AM
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
//@RefreshScope
@ConfigurationProperties(prefix = "config")
public class Config {
// @Value("${config.name}")
private String name;
// @Value("${config.type}")
private String type;
private String envSharedValue;
private String a;
private String b;
}
控制器类:
package com.changlu.nacosconfig.controller;
import com.changlu.nacosconfig.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Description:
* @Author: changlu
* @Date: 11:06 PM
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private Config config;
@GetMapping("/config")
public String getUserInfo() {
String res = config.toString();
return res;
}
}
配置类:
server:
port: 8088
spring:
application:
name: nacos-config
profiles:
active: pro
cloud:
nacos:
username: nacos
password: nacos
config:
server-addr: localhost:8848 # 注册到nacos的注册中心的服务地址
namespace: 477245fa-d5e1-47e0-9580-4a8e268c3f58 # 若是不指定,默认就是public
group: A_GROUP # 若是不 指定,默认是DEFAULT_GROUP
file-extension: yaml # 文件类型
shared-configs: # 共享变量
- data-id: nacos-config.yaml
group: DEFAULT_GROUP
refresh: true # 是否支持刷新
extension-configs: # 扩展配置文件
- data-id: nacos-config-a.yaml
group: A_GROUP
refresh: true # 是否支持刷新
- data-id: nacos-config-b.yaml
group: B_GROUP
refresh: true # 是否支持刷新
首先是多环境变量的解释:
接下来是多组共享变量的解释:
最后则是多组扩展配置文件的解释:
之后我们来进行测试一下:
①设置成dev来进行启动:
调用接口测试一下:
②接着设置成pro来测试一下:
没得问题!
一般nacos项目的话,会在本地配有一个bootstrap配置文件,然后远端配置好多环境配置文件,以及一些公共的配置项,这就可能用到共享配置以及扩展配置了!
那么在不同文件中具体写什么呢?
1、boostrap.yml
:应用名称,nacos的注册中心配置以及配置文件读取指定。
2、远端配置
:
配置项优先级介绍:
1、针对于多组配置如公共、扩展的。
上述两类配置都是数组,对同种配置,数组元素对应的下标越⼤,优先级越⾼。也就是排在后⾯的相同配置,将覆盖排在前⾯的同名配置。
extension-configs[3] > extension-configs[2] > extension-configs[1] > extension-configs[0
。2、不同种类配置的优先级:主配置 > 扩展配置(extension-configs) > 共享配置(shared-configs)。
看下我在阅读其他博文中给出的配置示例:
[1]. nacos与eureka的区别
[2]. Nacos简介
[3]. Nacos共享配置(shared-configs)和扩展配(extension-config)