Nacos——注册中心实践详解(全部代码看最后面,前面是细节)

1、Nacos Discovery 简介

在这里插入图片描述
使用 Spring Cloud Alibaba Nacos Discovery,可基于 Spring Cloud 的编程模型快速接入 Nacos服务注册功能。

服务发现是微服务架构体系中最关键的组件之一。如果尝试着用手动的方式来给每一个客户端来配置所有服务提供者的服务列表是一件非常困难的事,而且也不利于服务的动态扩缩容。Nacos Discovery 可以帮助您将服务自动注册到 Nacos 服务端并且能够动态感知和刷新某个服务实例的服务列表。除此之外,Nacos Discovery 也将服务实例自身的一些元数据信息-例如 host,port, 健康检查 URL,主页等内容注册到 Nacos。

2、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 该文件,来点击下载他。
提示:若大家的下载速度较慢,可以去我得百度网盘中下载

链接:https://pan.baidu.com/s/1dheVwbVmgE4k2pgVnUYivg
提取码:crrb

2.2 Nacos Server 目录的说明

将下载的 nacos-server-1.1.4 复制到我想放的目录下,我的是如下(解压后的):
在这里插入图片描述
解压完成后,进入 Nacos 目录里面:
在这里插入图片描述
目录解释:
bin:

可执行文件夹目录,包含:启动、停止命令等等

conf:

配置文件目录

target:

存放 naocs-server.jar

LICENSE:

授权信息,Nacos 使用 Apache License Version 2.0 授权

NOTICE:

公告信息

2.3 配置 Nacos Server

进入${Nacos}/conf 目录(也就是解压后的conf目录)里面,使用文件编辑器打开 application.properties 文件,这里面我使用的是 sublime text:

在这里插入图片描述
打开后,如下图所示:
在这里插入图片描述
Nacos 默认使用嵌入式数据库实现数据的存储,并不方便观察数据存储的基本情况,这里面我们修改为使用 Mysql 数据库做数据的存储,方便我们观察数据的结构。
在配置文件末尾添加如下配置:

spring.datasource.platform=mysql
db.num=1
#个人连接数据库的链接
db.url.0=jdbc:mysql://localhost:3307/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true 
#个人连接数据库的账号
db.user=root
#个人连接数据库的密码
db.password=489773

注意:

  • 上面的 url 地址是我的服务器地址,如果你的 mysql 安装在虚拟机或云服务器上面,就填写真实的地址。
  • db.user 用户名
  • db.password 密码

2.4 Mysql 表的导入

提示:Nacos 建议使用 5.7 以上的 Mysql 数据库,版本较低可能存储兼容性问题
我使用的 Mysql 数据库版本为 5.7
打开${Nacos}/conf/文件夹:
在这里插入图片描述

其中 nacos-mysql.sql 就是 nacos 提供给我们的 sql 语句。

新建数据库:在这里插入图片描述
点击确定完成创建。
导入 sql 语句:
在这里插入图片描述
选择我们 nacos-mysql.sql 文件:
在这里插入图片描述
点击开始,完成导入,已经成功导入,包含如下的表:
10

2.5 Nacos Server 的启动

上面工作都完成后,现在我们来启动一个单机版的 Nacos 服务器。
进入到${Nacos}/bin 目录里面:
在这里插入图片描述
双击 startup.cmd 文件,完成 nacos 的启动。
在这里插入图片描述

直到日志出现:
在这里插入图片描述

代表我们已经成功的启动了一个 Nacos 单机版的实例。
在浏览器里面输入:http://localhost:8848/nacos ,即可访问启动 Nacos 实例。
在这里插入图片描述
Nacos 默认用户名和密码都是 nacos。
输入正确的用户名和密码提交后,出现 Nacos 的控制台界面。(因为本人已经开发过项目了,所以里面有些数据,你们开启的时候里面是没有东西的)在这里插入图片描述
至此,Nacos Server 已经安装成功。

3、框架的搭建(使用)

在这里插入图片描述

3.1 创建 nacos-examples 的父项目

项目创建结构:
在这里插入图片描述
修改 nacos-examples 里面的 pom.xml 文件,在此我们引入:

  • spring-boot-starter-web (spring-boot-web 开启的最基础的依赖)
  • spring-cloud-alibaba-nacos-discovery(nacos 做服务发现的最基础的依赖)
    在添加这 2 个依赖:
<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>com.alibaba.cloud</groupId>
		<artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
	</dependency>
</dependencies>

修改nacos-examples项目的打包方式:

<packaging>pom</packaging>

最后,完整的 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>
        <artifactId>spring-cloud-alibaba-examples</artifactId>
        <groupId>com.zhz</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>nacos-examples</artifactId>

    <packaging>pom</packaging>
    <modules>
        <module>provider</module>
        <module>comsumer</module>
        <module>config-client</module>
    </modules>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>
</project>

3.2 创建服务的提供者 provider

服务提供者将为以后的服务消费者提供一些接口的供远程调用。
使用 IDEA 为 nacos-examples 创建一个子模块:
在这里插入图片描述
在这里插入图片描述

将 Next 进入下一步操作:
在这里插入图片描述
注意:我们的 parent 必须选择为 nacos-examples。

Name:provider(服务的提供者)

其他的项将自动的填充,不需要我们修改。

Provider 的依赖分析:

<?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>
        <artifactId>nacos-examples</artifactId>
        <groupId>com.zhz</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>provider</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>
</project>

我们的 provider 已经自动的从 nacos-exmaples 里面把这 2 个依赖继承过来了。

3.3 创建服务的消费者

服务消费者将远程调用服务提供者提供的接口。
使用 IDEA 为 nacos-examples 创建一个子模块:
在这里插入图片描述
在这里插入图片描述

将 Next 进入下一步操作:
在这里插入图片描述
注意:我们的 parent 必须选择为 nacos-examples。

Name:consumer(服务的提供者)

其他的项将自动的填充,不需要我们修改。

Consumer 的依赖分析:

<?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>
        <artifactId>nacos-examples</artifactId>
        <groupId>com.zhz</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>comsumer</artifactId>
</project>

我们的 consumer 已经自动的从 nacos-exmaples 里面把这 2 个依赖继承过来了。
至此,我们项目的骨架已经搭建完成。如下图所示:
在这里插入图片描述

4、使用 Nacos 做注册中心

4.1 provider 项目的完善

Provider 现在还是一个空的项目,里面没有任何的数据接口。

4.1.1 添加一个 application.yml 配置文件

我们给 provider 添加一个配置文件:
在这里插入图片描述
文件的名称为:
在这里插入图片描述
完成创建后,IDEA 能自动的识别该 yml 文件。
在这里插入图片描述

编辑该配置文件,添加如下的配置:

server:
  port: 8081
spring:
  application:
    name: nacos-provider
  cloud:  #nacos注册中心地址的配置法
    nacos:
      discovery:
        server-addr: localhost:8848   # nacos 注册中心的地址

配置说明:

  • server.port provider 服务端口为 8001 ;
  • spring.application.name 服务名称为 provider-service ;
  • spring.cloud.nacos.server-addr ,指定 Nacos 注册中心的地址;

4.1.2 添加一个启动类

Provider 还没有启动类,我们需要给他添加一个。
在这里插入图片描述
名称为:com.zhz.ProviderServiceApplication

在该类里面添加如下的代码:

package com.zhz;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * @author zhz
 * @date 2020/07/28
 **/
@SpringBootApplication
@EnableDiscoveryClient  //开启服务的发现和注册
public class ProviderServiceApplication {

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

4.1.3 添加一个 API 接口

提供者通过提供 API 接口供服务提供者调用。
在 provider 里面创建一个类:名称为 com.zhz.controller.EchoController

添加一个接口:

package com.zhz.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author zhz
 * @date 2020/07/28
 **/
@RestController
public class EchoController {

    /**
     *
     * @param message
     * @return
     */
    @GetMapping("/echo/{message}")
    public  ResponseEntity<String> echo(@PathVariable("message") String message){
        return ResponseEntity.ok(String.format("hello,%s,我是%s",message));
    }
}

该接口将会对访问的人输入一个 hello,xxx。

4.1.4 启动 provider 测试

在nacos界面上看,地址为:http://localhost:8848/nacos/#/serviceManagement?dataId=&group=&appName=&namespace=
在这里插入图片描述

4.2 consumer 项目的完成

Consumer 现在还是一个空的项目,里面没有任何的数据接口,也没有对服务的提供者进行调用。

4.2.1 添加一个 application.yml 配置文件

我们给 consumer 添加一个配置文件名称为:application.yml
IDEA 能自动的识别该配置文件的:
编辑该文件,给该文件添加如下的配置信息:

server:
  port: 8086
spring:
  application:
    name: nacos-comsumer
  cloud:  #nacos注册中心地址的配置法
    nacos:
      discovery:
        server-addr: localhost:8848

4.2.2 添加一个启动类

Consumer 现在还没有任何的启动类,我们需要给他添加一个。名称为:com.zhz.ConsumerApplication
创建成功后,在该类里面添加如下代码:

package com.zhz;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

/**
 * @author zhz
 * @date 2020/07/28
 **/
@SpringBootApplication
@EnableDiscoveryClient  //服务的发现和注册
public class ConsumerServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerServiceApplication.class,args);
    }
}

4.2.3 服务发现的测试

在comsumer服务中创建一个EchoConsumerController.java类,内容如下

package com.zhz.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * @author zhz
 * @date 2020/07/28
 **/
@RestController
public class EchoConsumerController {

    @Autowired
    private DiscoveryClient discoveryClient;

    @Autowired
    private RestTemplate restTemplate;
    /**
    * 服务发现
    */
    @GetMapping("/discovery/{serviceName}")
    public ResponseEntity<List<String>> discovery(@PathVariable String serviceName){
        /**
         * 通过服务的ID或者名称得到服务的实例列表
         */
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);

        if (instances==null||instances.isEmpty()){
            return ResponseEntity.notFound().build();
        }
        List<String> service = new ArrayList<>(instances.size());
        instances.forEach(instance->{
            service.add(instance.getHost()+":"+instance.getPort());
;        });
        return ResponseEntity.ok(service);
    }
}

启动 consumer-service项目,记得provider和comsumer端都要启动。观察两个项目是否成功注册到nacos中
在这里插入图片描述
在浏览器中输入:http://localhost:8086/discovery/nacos-provider
,如下则成功
在这里插入图片描述
输入一个不存在的服务名称:
在这里插入图片描述
代表,该服务还没有服务的提供者。

4.2.4 远程调用测试

在Comsumer的EchoConsumerController 中添加一下资料(我把前面的东西都合并了,放在下面)

package com.zhz.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * @author zhz
 * @date 2020/07/28
 **/
@RestController
public class EchoConsumerController {

    @Autowired
    private DiscoveryClient discoveryClient;

    @Autowired
    private RestTemplate restTemplate;
    
    @GetMapping("/discovery/{serviceName}")
    public ResponseEntity<List<String>> discovery(@PathVariable String serviceName){
        /**
         * 通过服务的ID或者名称得到服务的实例列表
         */
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);

        if (instances==null||instances.isEmpty()){
            return ResponseEntity.notFound().build();
        }
        List<String> service = new ArrayList<>(instances.size());
        instances.forEach(instance->{
            service.add(instance.getHost()+":"+instance.getPort());
;        });
        return ResponseEntity.ok(service);
    }
    @GetMapping("/rpcv1/{message}")
    public ResponseEntity<String> rpcv1(@PathVariable("message") String message){
        ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://localhost:8081/echo/{message}", String.class, message);
        if(responseEntity.getStatusCode()== HttpStatus.OK){
            return responseEntity.ok(String.format("远程调用成功,结果为"+responseEntity.getBody()));
        }
        return responseEntity.badRequest().body("远程调用失败");

    }
    @GetMapping("/rpcv2/{message}")
    public ResponseEntity<String> rpcv2(@PathVariable("message") String message){
        List<ServiceInstance> instances = discoveryClient.getInstances("nacos-provider");
        if (instances==null||instances.isEmpty()){
            return ResponseEntity.badRequest().body("当前服务没有服务的提供者");
        }
        ServiceInstance serviceInstance = instances.get(0);
        String instace=serviceInstance.getHost()+":"+serviceInstance.getPort();
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(
                String.format("http://%s/echo/{message}",instace),
                String.class,
                message);
        if(responseEntity.getStatusCode()== HttpStatus.OK){
            return responseEntity.ok(String.format("远程调用成功,结果为"+responseEntity.getBody()));
        }
        return responseEntity.badRequest().body("远程调用失败");
    }

    /**
     * 手写负载均衡算法
     * @param message
     * @return
     */
    @GetMapping("/rpcv3/{message}")
    public ResponseEntity<String> rpcv3(@PathVariable("message") String message){
        List<ServiceInstance> instances = discoveryClient.getInstances("nacos-provider");
        if (instances==null||instances.isEmpty()){
            return ResponseEntity.badRequest().body("当前服务没有服务的提供者");
        }
        ServiceInstance serviceInstance = loadBalanced(instances);
        String instace=serviceInstance.getHost()+":"+serviceInstance.getPort();
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(
                String.format("http://%s/echo/{message}",instace),
                String.class,
                message);
        if(responseEntity.getStatusCode()== HttpStatus.OK){
            return responseEntity.ok(String.format("远程调用成功,结果为"+responseEntity.getBody()));
        }
        return responseEntity.badRequest().body("远程调用失败");
    }

    /**
     * 从一个服务的实例列表里面选择一个服务的列表
     * @param instances 实例列表
     * @return 具体的实例
     */
    private ServiceInstance loadBalanced(List<ServiceInstance> instances) {
        Random random=new Random(System.currentTimeMillis());
        return instances.get(random.nextInt(instances.size()));
    }
    /**
     * 调用nacos的负载均衡算法
     * @param message
     * @return
     */
    @GetMapping("/rpcv4/{message}")
    public ResponseEntity<String> rpcv4(@PathVariable("message") String message){
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(
                "http://nacos-provider/echo/{message}",
                String.class,
                message);
        if(responseEntity.getStatusCode()== HttpStatus.OK){
            return responseEntity.ok(String.format("远程调用成功,结果为"+responseEntity.getBody()));
        }
        return responseEntity.badRequest().body("远程调用失败");
    }
}

在浏览器里面输入:http://localhost:8086/rpcv1/world

5、负载均衡测试

当服务压力突然变大时,我们需要通过对服务进行弹性伸缩和动态的扩容,让服务展示更强的并发能力和容错能力。

5.1、修改服务提供者的数据接口

修改服务提供者的接口,可以让我们很清晰的看到,我们当前调用的是那一台服务提供者。让我们来修改 provider 里面 EchoController 这个类

package com.zhz.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author zhz
 * @date 2020/07/28
 **/
@RestController
public class EchoController {

    @Value("${server.port}")
    private Integer port;//在一台主机上启动多个服务提供者,他的端口肯定不一样


    /**
     *
     * @param message
     * @return
     */
    @GetMapping("/echo/{message}")
    public  ResponseEntity<String> echo(@PathVariable("message") String message){
        return ResponseEntity.ok(String.format("hello,%s,我是%s",message,port));
    }
}

因为我们在同一台机器上启动多个服务提供者,那服务提供者的端口肯定不相同,我们在此使用 port 作为服务提供者的唯一标示。

  • @Value : 从 env 里面注入这个值

5.2 启动多个服务的提供者

先停止所有的服务:
在这里插入图片描述
在启动一个服务的提供者:
在这里插入图片描述
启动成功后:
在这里插入图片描述
启动其他 1 个:
在这里插入图片描述
进入编辑页面:

在这里插入图片描述
2 个操作:

  • Name:不能重复,这里我修改为 ProviderServiceApplication-2
  • Program arguments:–server.port=8090 这句话的意思是,在启动该服务时,添加一个变量: server.port=8081 ,类似我们使用这样的命令启动:
java -jar xxx.jar --server.port=8086
  • --server.port该 值 将 会 被 添 加 到 spring 的 env 里 面 , 并 且 该 方 式 的 优 先 级 高 于application.yml 里面的配置值。所以,系统会使用该 port 来启动服务。
    修改完毕后,点击 ok。
    启动程序,我自己一共创建了3个服务者
    在这里插入图片描述
    观察nacos,看实例:
    在这里插入图片描述

5.3、测试负载均衡

修改 consumer 里面的 ConsumerApplication ,在里面的末尾添加如下的代码:

@Autowired
private LoadBalancerClient loadBalancerClient ;
@GetMapping("/choose/{serviceName}")
public ResponseEntity<String> 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:8086/choose/provider-service

5.4、更简单的远程调用测试

在之前,我们在 consumer 使用 RestTemplate 调用 provider 时,手动实现了负载均衡,url的拼接:
在这里插入图片描述
代码相当的冗余。现在,我们使用 Ribbon 的方式来实现:
在注入 RestTemplate 的方法上添加注解,在ConsumerServiceApplication 中添加:

package com.zhz;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

/**
 * @author zhz
 * @date 2020/07/28
 **/
@SpringBootApplication
@EnableDiscoveryClient  //服务的发现和注册
public class ConsumerServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerServiceApplication.class,args);
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

comsumer中的EchoConsumerController.java添加:

@GetMapping("/rpc/ribbon/{message}")
public ResponseEntity<String> rpcByRibbon(@PathVariable("message") String message){
	ResponseEntity<String> 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("调用失败,nacos-provider 的相应码为:"+responseEntity.getStatusCode()) ;
}

然后自行启动测试即可。

6、Nacos Discovery 对外暴露的 Endpoint

Endpoint 本身对外界隐藏显示,我们需要在配置里面开启对 Endponit 的显示支持。
修改 application.yml 配置文件,在里面添加如下的配置:

management:
  endpoints:
    web:
      exposure:
        include: "*"

说明:

  • exposure.include:对外界保留那些 Endpoint,若是所有则使用* ;

6.3 查询效果

重启项目,浏览器访问:
http://localhost:8081/actuator/nacos-discovery
效果为:
在这里插入图片描述

7、Nacos Discovery Starter 更多的配置项

配置项Key默认值说明
服务端spring.cloud.nacos.discovery.serverNacos Server 启动监听的 ip 地址和端口
服务名spring.cloud.nacos.discovery.service${spring.application.name}给当前的服务命名
服务分组spring.cloud.nacos.discovery.groupDEFAULT_GROUP设置服务所处的分组
权重spring.cloud.nacos.discovery.weight1取值范围 1 到 100,数值越大,权重越大
网卡名spring.cloud.nacos.discovery.network-interface当 IP 未配置时,注册的 IP 为此网卡所对应的 IP 地址,如果此项也未配置,则默认取第一块网卡的地址
注册的IP地址spring.cloud.nacos.discovery.ip优先级最高
注册的端口spring.cloud.nacos.discovery.port-1默认情况下不用配置,会自动探测
命名空间spring.cloud.nacos.discovery.namespace常用场景之一是不同环境的注册的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。
AccessKeyspring.cloud.nacos.discovery.access-key当要上阿里云时,阿里云上面的一个云账号名
SecretKeyspring.cloud.nacos.discovery.secret-key当要上阿里云时,阿里云上面的一个云账号密码
Metadataspring.cloud.nacos.discovery.metadata使用 Map 格式配置,用户可以根据自己的需要自定义一些和服务相关的元数据信息
日志文件名spring.cloud.nacos.discovery.log-name
集群spring.cloud.nacos.discovery.cluster-nameDEFAULT配置成 Nacos 集群名称
接入点spring.cloud.nacos.discovery.enpointUTF-8地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址
是否集成 Ribbonribbon.nacos.enabledtrue一般都设置成 true 即可
是否开启Nacos Watchspring.cloud.nacos.discovery.watch.enabledtrue可以设置成 false 来关闭 watch

8、总结

在这里插入图片描述

8.1、spring-cloud-alibaba-examples配置

8.1.1、pom配置

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zhz</groupId>
    <artifactId>spring-cloud-alibaba-examples</artifactId>
    <version>1.0</version>
    <modules>
        <module>nacos-examples</module>
    </modules>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <packaging>pom</packaging>

    <properties>
        <spring-cloud.version>Hoxton.SR3</spring-cloud.version>
        <com-alibaba-cloud.version>2.2.0.RELEASE</com-alibaba-cloud.version>
    </properties>

    <dependencyManagement>
        <dependencies>

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${com-alibaba-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

8.2、nacos-examples

8.2.1、pom

<?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>
        <artifactId>nacos-examples</artifactId>
        <groupId>com.zhz</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>provider</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

</project>

8.3、provider

8.3.1、pom

<?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>
        <artifactId>nacos-examples</artifactId>
        <groupId>com.zhz</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>provider</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

</project>

8.3.2、application.yml

server:
  port: 8081
spring:
  application:
    name: nacos-provider
  cloud:  #nacos注册中心地址的配置法
    nacos:
      discovery:
        server-addr: localhost:8848  # nacos 注册中心的地址
        enabled: false # 关闭/启动nacos的注册中心功能
        ip: provider-xxx # 配置nacos的ip 地址
management:
  endpoints:
    web:
      exposure:
        include: "*"

8.3.3、ProviderServiceApplication

package com.zhz;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient // 开启服务的发现和注册
public class ProviderServiceApplication {

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

8.2.4、EchoController

package com.zhz.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class EchoController {

    @Value("${server.port}")
    private Integer port ; // 在一台主机上启动多个服务提供者,它的端口肯定不同
    /**
     * reply message
     * @param message
     * @return
     */
    @GetMapping("/echo/{message}")
    public ResponseEntity<String> echo(@PathVariable("message")String message){

        return ResponseEntity.ok(String.format("hello,%s,我是%s",message,port)) ;

    }
}

8.4、comsumer

8.4.1、pom

<?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>
        <artifactId>nacos-examples</artifactId>
        <groupId>com.zhz</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>consumer</artifactId>
</project>

8.4.2、application.yml

server:
  port: 8086
spring:
  application:
    name: nacos-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

8.4.3、启动类ConsumerServiceApplication.java

package com.zhz;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient // 服务的发现和注册
public class ConsumerServiceApplication {

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

    @LoadBalanced
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate() ;
    }
}

8.4.4、测试类EchoConsumerController.java

package com.zhz.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * @author zhz
 * @date 2020/07/28
 **/
@RestController
public class EchoConsumerController {

   @Autowired
    private DiscoveryClient discoveryClient ;// 快速服务的发现
    
	@Autowired
    private RestTemplate restTemplate;
    
    @GetMapping("/discovery/{serviceName}")
    public ResponseEntity<List<String>> discovery(@PathVariable("serviceName") String serviceName){
    	/**
         * 通过服务的ID / 名称得到服务的实例列表
         */
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);

        if(instances==null || instances.isEmpty()){
            return ResponseEntity.notFound().build() ;
        }

        List<String> services = new ArrayList<>(instances.size());

        instances.forEach(instance->{
            services.add(instance.getHost()+":"+instance.getPort());
        });

        return ResponseEntity.ok(services) ;
    }
    
	@GetMapping("/rpcv1/{message}")
    public ResponseEntity<String> rpcV1(@PathVariable("message") String message){
        ResponseEntity<String> 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<String> rpcV2(@PathVariable("message") String message){
        List<ServiceInstance> 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<String> 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<String> rpcV3(@PathVariable("message") String message){
        List<ServiceInstance> 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<String> 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("远程调用失败") ;
    }

    /**
     * 从一个服务的实例列表里面选择一个服务的实例
     * @param instances
     * 实例列表
     * @return
     * 具体的实例
     */
    private ServiceInstance loadbalance(List<ServiceInstance> instances) {
        Random random = new Random(System.currentTimeMillis());
        return instances.get(random.nextInt(instances.size())) ;
    }


    @GetMapping("/rpcv4/{message}")
    public ResponseEntity<String> rpcV4(@PathVariable("message") String message){
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(
               "http://nacos-provider/echo/{message}",
                String.class,
                message
        );
        if(responseEntity.getStatusCode()==HttpStatus.OK){
            return ResponseEntity.ok(String.format("远程调用成功,结果为%s",responseEntity.getBody())) ;
        }
        return ResponseEntity.badRequest().body("远程调用失败") ;
    }
}

下面是本人的公众号:(有兴趣可以扫一下,文章会同步过去)
在这里插入图片描述

我是小白弟弟,一个在互联网行业的小白,立志成为一名架构师
https://blog.csdn.net/zhouhengzhe?t=1

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhz小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值