《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 http://www.iocoder.cn/Spring-Boot/registry-nacos/ 「芋道源码」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

1. 概述

《Nacos 安装部署》中,我们已经学习了如何搭建一个 Nacos 服务。如果还没有的胖友,赶紧先去简单学习下,重点是跟着该文「2. 单机部署」小节,自己搭建一个 Nacos 服务。

本文,我们来学习下如何在 Spring Boot 中,将 Nacos 作为一个注册中心,实现分布式环境下的服务注册与发现。

友情提示:对 Nacos 作为配置中心感兴趣的胖友,可以看看《芋道 Spring Boot 配置中心 Nacos 入门》文章。

2. 注册中心原理

在使用注册中心时,一共有三种角色:服务提供者(Service Provider)、服务消费者(Service Consumer)、注册中心(Registry)。

在一些文章中,服务提供者被称为 Server,服务消费者被称为 Client。胖友们知道即可。

三个角色交互如下图所示:注册中心原理

  • Provider:

    • 启动时,向 Registry 注册自己为一个服务(Service)的实例(Instance)。
    • 同时,定期向 Registry 发送心跳,告诉自己还存活。
    • 关闭时,向 Registry 取消注册
  • Consumer:

    • 启动时,向 Registry 订阅使用到的服务,并缓存服务的实例列表在内存中。
    • 后续,Consumer 向对应服务的 Provider 发起调用时,从内存中的该服务的实例列表选择一个,进行远程调用。
    • 关闭时,向 Registry 取消订阅
  • Registry:

    • Provider 超过一定时间未心跳时,从服务的实例列表移除。
    • 服务的实例列表发生变化(新增或者移除)时,通知订阅该服务的 Consumer,从而让 Consumer 能够刷新本地缓存。

当然,不同的注册中心可能在实现原理上会略有差异。例如说,Eureka 注册中心,并不提供通知功能,而是 Eureka Client 自己定期轮询,实现本地缓存的更新。

另外,Provider 和 Consumer 是角色上的定义,一个服务同时即可以是 Provider 也可以作为 Consumer。例如说,优惠劵服务可以给订单服务提供接口,同时又调用用户服务提供的接口。

3. 快速入门

示例代码对应仓库:lab-44-nacos-discovery-demo

本小节,我们来搭建一个 Spring Boot 示例,注册到 Nacos 服务器上。

3.1 引入依赖

pom.xml 文件中,引入相关依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>lab-44-nacos-discovery-demo</artifactId>

<dependencies>
<!-- 实现对 SpringMVC 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- 实现对 Nacos 作为注册中心的自动化配置 -->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>nacos-discovery-spring-boot-starter</artifactId>
<version>0.2.4</version>
</dependency>
</dependencies>

</project>

3.2 配置文件

application.yml 中,添加 Nacos 配置,如下:

spring:
application:
name: demo-application # 应用名

nacos:
# Nacos 配置中心的配置项,对应 NacosDiscoveryProperties 配置类
discovery:
server-addr: 127.0.0.1:18848 # Nacos 服务器地址
auto-register: true # 是否自动注册到 Nacos 中。默认为 false。
namespace: # 使用的 Nacos 的命名空间,默认为 null。
register:
service-name: ${spring.application.name} # 注册到 Nacos 的服务名
group-name: DEFAULT_GROUP # 使用的 Nacos 服务分组,默认为 DEFAULT_GROUP。
cluster-name: # 集群名,默认为空。

spring.application.name 配置项,应用名。默认情况下,如果我们不设置 nacos.discovery.register.service-name 配置项,Spring Boot 注册到 Nacos 的服务名为它。

nacos.discovery 配置项,为 Nacos 作为注册中心的配置,对应 NacosDiscoveryProperties 配置类。

  • server-addr:Nacos 服务器地址。

  • auto-register:是否自动注册到 Nacos 中。默认为 false。😈 这里,我们设置为 true,自动注册到 Nacos 中。

  • namespace:使用的 Nacos 的命名空间,默认为 null

    FROM 《Nacos 文档 —— Nacos 概念》

    命名空间
    用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。 * 也就是说,如果我们多个环境共享同一个 Nacos 服务,可以通过 namespace 来区分正式、预发布、UAT、开发等环境。

  • register:注册服务的实例的信息,对应 Register 类。

    • service-name:服务名称。未配置的情况下,默认使用 spring.application.name 配置项。

    • group-name:使用的 Nacos 服务分组,默认为 DEFAULT_GROUP

      FROM 《Nacos 文档 —— Nacos 概念》

      服务分组
      不同的服务可以归类到同一分组。

    • cluster-name:使用的 Nacos 服务集群,默认为空。

      FROM 《Nacos 文档 —— Nacos 概念》

      虚拟集群
      同一个服务下的所有服务实例组成一个默认集群, 集群可以被进一步按需求划分,划分的单位可以是虚拟集群。

😜 突然看到 Nacos 一大片的概念,胖友会有点懵逼。问题不大,跟着示例继续往下,会逐步有感觉的。

更多 Nacos Discovery Spring Boot 配置项,可以看看《nacos-spring-boot-project —— WIKI》文章。

3.3 ProviderController

cn.iocoder.springboot.lab44.nacosdemo.controller 包下,创建 ProviderController 类,作为 Provider 提供示例 API 接口。代码如下:

@RestController
@RequestMapping("/provider")
public class ProviderController {

@GetMapping("/demo")
public String provider() {
return "echo";
}

}

3.4 ConsumerController

cn.iocoder.springboot.lab44.nacosdemo.controller 包下,创建 ConsumerController 类,模拟 Consumer 调用「3.3 ProviderController」提供示例 API 接口。代码如下:

友情提示:通过直接使用当前 Spring Boot 示例,来模拟 Consumer 角色,方便简洁。

@RestController
@RequestMapping("/consumer")
public class ConsumerController {

@NacosInjected
private NamingService namingService;

private RestTemplate restTemplate = new RestTemplate();

@GetMapping("/demo")
public String consumer() throws IllegalStateException, NacosException {
// <1> 获得实例
Instance instance = null;
if (false) {
List<Instance> instances = namingService.getAllInstances("demo-application");
// 获得首个实例,进行调用
instance = instances.stream().findFirst()
.orElseThrow(() -> new IllegalStateException("未找到对应的 Instance"));
} else {
instance = namingService.selectOneHealthyInstance("demo-application");
}
// <2> 执行请求
return restTemplate.getForObject("http://" + instance.toInetAddr() + "/provider/demo",
String.class);
}

}

  • namingService 属性,NamingService 对象,用于调用 Nacos 作为命名服务提供的 API。不过它比较特殊,需要通过 @NacosInjected 注解,来进行注入到 Bean 中。
  • /consumer/demo 接口,模拟 Consumer 调用「3.3 ProviderController」提供示例 API 接口。
    • <1> 处,获得一个 demo-application 服务对应的实例。
    • <2> 处,使用 RestTemplate 向获得的服务实例,发起 HTTP 远程调用。

3.5 Application

创建 Application.java 类,配置 @SpringBootApplication 注解即可。代码如下:

@SpringBootApplication
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}

}

3.6 简单测试

① 启动 Spring Boot 应用,开始我们本轮的测试。此时,控制台输出 Spring Boot 应用注册到 Nacos 中的日志如下:

2020-01-24 22:34:03.592  INFO 39657 --- [           main] c.a.b.n.d.a.NacosDiscoveryAutoRegister   : Finished auto register service : demo-application, ip : 192.168.31.185, port : 8080

  • 从日志中,我们可以看到 Spring Boot 注册到 Nacos 中的基本信息。

打开 Nacos UI 界面的「服务列表」菜单,进入「服务列表」功能。此时,我们可以看到 demo-application 服务。如下图所示:服务列表

② 使用浏览器,访问 http://127.0.0.1:8080/consumer/demo 接口,模拟 Consumer 调用「3.3 ProviderController」提供示例 API 接口。返回结果如下:

echo

  • 调用成功,美滋滋~

打开 Nacos UI 界面的「订阅者列表」菜单,进入「订阅者列表」功能。同时,我们使用 demo-application 服务,进行搜索。此时,我们可一个订阅者。如下图所示:订阅者列表

666. 彩蛋

至此,我们已经完成了在 Spring Boot 项目中使用 Nacos 作为注册中心。不过一般使用到注册中心,公司一般已经采用微服务架构。此时,更多的采用以 Spring Cloud 作为基础选型,可以考虑使用 spring-cloud-alibaba-nacos-discovery 项目。

友情提示:如果想要了解 Spring Cloud Alibaba 的胖友,可以阅读《芋道 Spring Cloud Alibaba 注册中心 Nacos 入门》文章。

目前感觉,在 Spring Boot 项目中使用 Nacos 作为注册中心,貌似场景并不多。暂时能想到的好处,可以方便通过 Nacos 知道哪些 Spring Boot 节点正在启动中。

文章目录
  1. 1. 1. 概述
  2. 2. 2. 注册中心原理
  3. 3. 3. 快速入门
    1. 3.1. 3.1 引入依赖
    2. 3.2. 3.2 配置文件
    3. 3.3. 3.3 ProviderController
    4. 3.4. 3.4 ConsumerController
    5. 3.5. 3.5 Application
    6. 3.6. 3.6 简单测试
  4. 4. 666. 彩蛋