新公司这边配置中心和服务发现采用的是Spring Cloud Alibaba的Nacous,以前我这边写微服务用的是SpringCloud的Eureka注册中心,在我的博客springcloud五大组件永远滴神——成神之路中也详细分析了Eureka服务注册和发现中心的用法,大家可以想去了解Eureka的也可以去看那篇文章详细了解,这篇呢我就吧最近背着大家偷偷学的阿里巴巴的Nacos知识点来给大家一起分享下,毕竟和大家分享知识,不仅仅能够帮助你们,同样也能够帮助我理解更多和记忆更深,分享就是帮助他人,成长自己的过程嘛,来吧,老规矩,废话少说,上干货。

1、Nacos是什么?

       每学习一项新的知识点,首先就是要了解它是什么?它又能干什么?这是千古不变的。Nacos是Dynamic Naming and Configuration Service简称,Na是naming即是注册,co是configuration即配置,service是该注册和配置中心都是以服务为核心。服务在nacos中是一等公民。

       Nacos注册中心为CS架构模式,server采用Java编写,为client提供注册服务与配置服务。client可以用多种语言实现,client与微服务嵌套在一起。使用Nacos肯定是先下载Nacos Server,然后启动运行;然后client服务往server端进行注册与发现。这里的话我就不讲Nacos Server如何下载与安装了,大家可以自行百度哦。

2、Nacos 简单功能的介绍与使用

       安装好Nacos Server后,大家可以访问地址http://127.0.0.1:8848/nacos/#/login来登录Nacos,默认账号密码是nacos,nacos;大家输入账号密码后登录进去是如下页面:

在这里插入图片描述       上图中大家可以发现左侧的菜单栏中分为配置管理服务管理集群管理三大部分,下面我简单的给大家介绍下这三大部分的含义和简单用法。

2.1、配置管理

       配置管理,即是对配置中心的管理;配置中心就是将配置文件从应用中剥离出来进行统一管理,不需要我们的服务自己去管理配置。其管理配置流程大致如下图所示:

image-20210518152838877

       Namespace命名空间、Group分组、集群这些都是为了进行归类管理,把服务和配置文件进行归类,
        分类之后就可以实现一定的效果,比如隔离,对于服务来说,不同命名空间中的服务不能够互相访问调用

img

       Namespace:命名空间,对不同的环境进行隔离,比如隔离开发环境、测试环境和生产环境

  • Group:分组,将若干个服务或者若干个配置集归为一组,通常习惯一个系统归为一个组
  • Service:某一个服务,比如简历微服务
  • DataId:配置集或者可以认为是一个配置文件

       Nacos抽象出了Namespace、Group、Service、DataId等概念,具体代表什么取决于怎么用(非常灵 活),推荐用法如下

概念描述
Namespace代表不同的环境,如开发dev、测试test、生产环境prod
Group代表某项目,比如拉勾云项目
Service某个项目中具体xxx服务
DataId某个项目中具体的xxx配置文件

       namespace+group+Data Id在页面如下所示:

image-20210518150809789

       新建配置如下所示:

image-20210518154806001

image-20210518155009876

       好了以上就是配置管理的简单使用。
       2022年04月01日来给大家继续踩个坑,nacos的yml配置文件名称必须要有.yaml;举例说明:项目名称为spring.applicatuon.name=test,这里你会以为在nacos中读取的配置文件名称为test,那么你就错了,实际读取的名称为test.yaml,一定要注意,否则读取失败。
图片展示如下所示:
在这里插入图片描述在这里插入图片描述

2.2、服务管理

       服务管理顾名思义就是管理各种微服务,其页面如下所示:

image-20210518160028681

2.3、集群管理

       集群管理就是对毫无关联的各个Nacos进行统一起来,构成一个集群来进行统一。

image-20210518160239281

3、Nacos配置中心简单demo

       这里我先简单的介绍下如何读取Nacos中的配置文件,这种事最原始的,在真正的企业开发过程中是不会使用的。

       首先我们在Nacos Server中创建配置中心文件。

image-20210518161957695
       配置内容大家根据自己的实际情况进行编写。

       然后编写代码如下所示:

package com.ygl.nacos;

import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;

import java.util.Properties;
import java.util.concurrent.Executor;

/**
 * @author yangaoling
 * @version 1.0
 * @date 2021/4/30 14:50
 */
public class SimpleDemoMain {

    public static void main(String[] args) throws NacosException, InterruptedException {
        //使用nacos client 远程获取nacos服务上的配置信息
        //nacos地址+端口号
        String serverAddr = "127.0.0.1:8848";
        //nameSpace
        //注意namespace中的s是小写,千万不能写错,否则就不行
        String namespace = "b6cb281f-df22-4f43-9048-ff16ebcdec65";
        //group
        String group = "DEFAULT_GROUP";
        //data id
        String dataId = "nacos-simple-demo.yaml";
        
        Properties properties = new Properties();
        properties.put("serverAddr", serverAddr);
        properties.put("namespace", namespace);
        //获取配置
        ConfigService configService = NacosFactory.createConfigService(properties);
        //String dataId, String group, long timeoutMs
        String config = configService.getConfig(dataId, group, 5000);
        System.out.println("获取内容:" + config);
        //添加配置监听
        //String dataId, String group, Listener listener
        configService.addListener(dataId, group, new Listener() {
            @Override
            public Executor getExecutor() {

                return null;
            }

            //当配置有变化的时候获取通知
            @Override
            public void receiveConfigInfo(String s) {

                System.out.println("变化啦:" + s);
            }
        });

        //模拟监听(来个死循环)
        while (true) {
            //休眠两秒
            Thread.sleep(2000);
        }
    }

}

       我简单的讲解下代码思维逻辑:

       1、创建Properties配置属性,往属性properties中添加地址serverAddr,serverAddr包括nacos地址和端口号,例如:127.0.0.1:8848;再添加命名空间namespace,注意一定不要写错这两个哈,还有namespace是写后面一行号,如下图所示:

image-20210518162851415

       2、根据服务配置地址和命名空间来获取所有配置文件,ConfigService configService = NacosFactory.createConfigService(properties);这行代码就是获取所有配置文件。

       3、根据Data Id和group来获取具体的配置文件内容;String config = configService.getConfig(dataId, group, 5000);这行代码的左后一个5000含义就是代表获取超时时间是5000ms。config的内容就是该配置文件的具体内容。

       4、上述代码中还添加了个配置监听,它的作用就是当我们更改配置文件内容重新发布后,这里会进行实时监听。

       代码运行结果如下图所示:

image-20210518163951179

4、Nacos配置中心集成Spring Cloud

       刚刚第三部分中,我们讲了java简单使用Nacos的Demo,通过上述代码我们明显可以发现如果在开发中那样使用Nacos的话真的太麻烦了,接下来我们来讲解Spring Cloud开发中如何使用Nacos。

4.1、创建maven项目nacos-config,然后引入部份依赖

       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.ygl.nacos</groupId>
    <artifactId>nacos-config</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>service1</module>
        <module>service2</module>
    </modules>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.1.3.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

       上述依赖引入的是alibaba的cloud下的dependencies依赖;springframework的cloud下的dependencies依赖;sprngBoot的dependencies依赖。

4.2、创建service1模块

       创建成功首先引入alibaba下的nacos-config依赖和springBoot下的starter-web依赖,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>nacos-config</artifactId>
        <groupId>com.ygl.nacos</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service1</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

</project>

       这里引入了阿里巴巴的nacos-config依赖和starter-web依赖。

       接下来编写yml配置文件,代码如下:

server:
  port: 56010 #端口号

spring:
  application:
    name: service1 #spring名称
  cloud:
    nacos:
      config:
        # 关闭从nacos中读取配置
        # enabled: false
        server-addr: 127.0.0.1:8848 # 配置中心地址
        file-extension: yaml # dataId的名称就是application的name加file-extension  service1.yaml
        namespace: b6cb281f-df22-4f43-9048-ff16ebcdec65 # 命名空间
        group: TEST_GROUP # 组名

        #共享data-id方式
        #自定义共享data-id,它只认 DEFAULT_GROUP组的配置文件
#        shared-dataids: ext-config-common01.properties,ext-config-common02.properties,ext-config-common03.properties
#        refreshable-dataids: ext-config-common01.properties

        #扩展data-id方式   扩展配置
        #在默认的组 DEFAULT_GROUP,不支持配置的动态刷新
        ext-config[0]:
          data-id: ext-config-common01.properties
        #不在默认的组,不支持动态刷新
        ext-config[1]:
          data-id: ext-config-common02.properties
          group: GLOBALE_GROUP
        #不在默认的组,支持动态刷新
        ext-config[2]:
          data-id: ext-config-common03.properties
          group: REFRESH_GROUP
          refresh: true #动态刷新


       yml中的各个含义我在后面注释中已经详细注明,这里我再详细说几点:

       1、server-addr是配置中心地址;

       2、file-extension文件类型,注意,这里要访问的Data Id名称是由application.name+file-extension;这里的data id名称是:service.yaml;

       3、namespace是命名空间名称;

       4、group是组名;

       5、ext-confid[]中是扩展的data-id的方式,不再过多详述。

注意:最最最重要的是这里的nacos配置一定要写在bootstrap.yml中,如果你写在application.yml中将是无法生效读取的。

       nacos中的service.yml配置文件如下面代码所示:

common:
    name: service1 config new
    school: qinghua

       controller层测试是否能够读取到nacos中的service1.yml内容测试代码如下所示:

package com.ygl.nacos.service2.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author yangaoling
 * @version 1.0
 * @date 2021/4/30 17:16
 */
@RestController
public class TestController {

    @Autowired
    private ConfigurableApplicationContext applicationContext;
	
    //这里采用Value注解直接将配置文件中的common.name的值注入进config1
   @Value("${common.name}")
   private String config1;

    @GetMapping("/getConfigs")
    public String getConfigs() {

        System.out.println("======"+config1);
        //获取nacos配置文件key为common.name的值
        return applicationContext.getEnvironment().getProperty("common.name");
    }

}

       启动类和平常没任何区别,这里就不再过多描述,

       启动项目后即可查看到读取的配置文件内容。

5、Nacos服务注册与发现

       上面章节中给大家分享了Nacos配置中心,这是Nacos中一个重要功能,接下来本章节中给大家介绍Nacos的还有重要功能之一:服务发现与注册。

       什么是注册中心、服务注册、服务发现?

       我先给大家打个比方来方便大家了解这三者的关系,咱们就拿买房者、卖房者,房屋中介这三个来对比。卖房者将房子交给房屋来管理就类似服务注册,房屋中介管理房屋买卖类似注册中心,买房者从中介了解房子信息就类似服务发现。下图表示其关系:
image-20210519104134761       我们可以将注册中心拆解成两部分,也就是注册、中心,注册的意思也见名知意,就是将某个东西注册到某个平台上,平台管理我们注册的东西,而中心就可以看成一个统一管理信息的平台,两个部分连起来就是注册中心,也就是统一管理所有注册信息的平台。

       而服务注册指的是服务在启动时将自身的信息注册到注册中心中,方便信息进行统一管理。服务注册是客户端向注册中心提交信息的动作。
image-20210519104747890
       服务发现指的是从注册中心获取对应服务的信息。服务发现是客户端向注册中心获取信息的动作。
image-20210519104944423
       服务消费者需要知道服务提供者的信息,比如 IP、 端口等信息,才能发起远程调用,所以需要通过拉取的动作从注册中心拉取对应服务的信息,然后发起调用。
image-20210519105352471       通过上面举例和画图,相信大家对服务注册、注册中心和服务发现有较深理解。

       注册中心原理:
img
       Nacos服务分级模型:
在这里插入图片描述       接下来在项目中完成配置管理和服务注册和发现功能。

       首先来个比较简单的生产者消费者的项目,直接将生产者注入进注册中心,然后消费者也注册进注册中心,然后消费者利用Feign来获取所需要的服务数据,这种是类似http请求的模式。

5.1、搭建项目,创建父工程nacos-discovery

       然后引入依赖,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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.ygl.nacos</groupId>
    <artifactId>nacos-discovery</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>quickstart-provider</module>
        <module>quickstart-consumer</module>
        <module>nacos-micro-service</module>
    </modules>
    <packaging>pom</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.1.3.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

5.2、创建生产者模块quickstart-provider

       首先引入nacos的discovery依赖,starter-web依赖和feign组件,pom.cml依赖如下所示:

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

    <artifactId>quickstart-provider</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

    </dependencies>
</project>

       然后创建application.yml配置文件,设置要将服务注册到注册中心的地址和命名空间,application.yml配置文件如下所示:

server:
  port: 56010

spring:
  application:
    name: quickstart-provider
  cloud:
    nacos:
      discovery:
        # 注册中心地址
        server-addr: 127.0.0.1:8848
        # 注册中心命名空间
        namespace: b6cb281f-df22-4f43-9048-ff16ebcdec65
# 日志有关配置
logging:
  level:
    root: info
    org.springframework: info

       创建controller层,写测试接口,代码如下:

@RestController
public class ProviderController {

    //添加打印日志
    private static final Logger LOG = LoggerFactory.getLogger(ProviderController.class);

    /**
     * 测试
     *
     * @Author: ygl
     * @Date: 2021/5/13
     */
    @GetMapping("/service")
    public String service() {
        LOG.info("provider invoke");
        return "provider invoke";
    }

}

       这里和平常写的没有任何区别

       最后写代码启动类,这里和平常启动类要有区别与不同了,要将该服务注册进注册中心,要添加开启服务发现注解@EnableDiscoveryClient和启用feign注解@EnableFeignClient;启动类代码如下所示:

package com.ygl.nacos;

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

import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * @author yangaoling
 * @version 1.0
 * @date 2021/5/13 17:45
 */
@SpringBootApplication
//开启服务发现客户端 和@EnableEurekaClient注解一样功能 都是能够让注册中心能够发现,扫描到该服务。
@EnableDiscoveryClient
//启用feign客户端
@EnableFeignClients
public class NacosProviderApp {

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

}

       这里我们就完成了生产者的模块的编写,启动该模块后,我们就能够将该项目注册进注册中心,在注册中心中能够看看到该项目,如图所示:
image-20210519145731026       点击详情后,可以看到该服务的详情,包括IP、端口、权重和健康状态等等。
image-20210519145858390       点击编辑,可以编辑部分内容,注意下权重,权重越大,在轮询调用的过程中被选中的概率越高。
image-20210519150031846

5.3、创建消费者模块quickstart-consumer

       老规矩,先引入我们所需要的依赖:nacos的discovery依赖、starter-web依赖和openfeign依赖。代码如下所示:

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

    <artifactId>quickstart-consumer</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

    </dependencies>

</project>

       创建application.yml文件,设置注册中心地址和命名空间,代码如下所示:

server:
  port: 56020

spring:
  application:
    name: quickstart-consumer
  cloud:
    nacos:
      discovery:
        server-addr: 49.235.125.139:8848
        namespace: b6cb281f-df22-4f43-9048-ff16ebcdec65

       创建提供者客户端接口,利用feign组件从注册中心中获取其服务接口,代码如下所示:

//注解中的值是提供者中application.yml文件中spring.application.name的值
@FeignClient("quickstart-provider")
public interface ProviderClient {
	
    //注意这个接口必须与生产者接口保持一致,任何地方都不可以不一样,否则将失败
    @GetMapping("/service")
    public String service();

}

       创建controller层,直接调用服务生产者接口。代码如下所示:

@RestController
public class ConsumerController {

    private static final Logger LOG = LoggerFactory.getLogger(ConsumerController.class);

    //动态代理对象,内部远程调用服务生产者
    @Autowired
    ProviderClient providerClient;

    @GetMapping("/service")
    private String service() {
        LOG.info("consumer invoke");
        String service = providerClient.service();
        return "consumer invoke :" + service;
    }

}

       利用@Autowired注解将服务生产者从注册中心拉取,直接调用即可,运行即可。

       启动类上仍然是添加开启服务发现注解和开启feign注解,代码如下:

@SpringBootApplication
//开启服务发现客户端 和@EnableEurekaClient注解一样功能 都是能够让注册中心能够发现,扫描到该服务。
@EnableDiscoveryClient
//启用feign客户端
@EnableFeignClients
public class NacosConsumerApp {

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

}

       启动运行后,该服务将会注册进nacos注册中心中,而且调用接口,将会调取生产者服务暴露的service接口。这是简单利用http来远程调用服务的方式。

5.4、Spring Cloud Alibaba 综合集成架构演示

前面讲到,Spring Cloud是一个较为全面的微服务框架集,集成了如服务注册发现、配置中心、消息总线、负载均衡、断路器、API网关等功能实现。而在网上经常发现Spring Cloud与阿里的Dubbo进行选择对比,这样比较其实是很不恰当,前者是一套较为完善的架构方案,而Dubbo只是服务治理与RPC实现方案。

       在此之前,我们已经学到如何使用Spring Cloud Alibaba来集成Nacos与Spring Cloud的应用,并且在此之下可以和传统的Spring Cloud应用一样的使用Ribbon或Feign来微服务之间的协作,由于Feign是基于Http Restful的调用,在高并发的性能下不够理想,RPC方案能否切换为Dubbo?Spring Cloud与阿里系若干组件能否完美集成?接下来就带领大家集成一个微服务基础架构。

5.4.1、总体架构

系统架构图:

image-20210519163539258

       组件说明:

API网关: 系统统一入口,屏蔽架构内部结构,统一安全拦截,采用Zuul实现。

application1: 应用1,模拟应用,提供http接口服务。

service-1: 微服务1,模拟微服务,提供dubbo接口服务。

service-2: 微服务2,模拟微服务,提供dubbo接口服务。

调用流程:

​        所有访问系统的请求都要经过网关,网关转发Http请求至application-1,application-1使用dubbo调用service1完成自身业务,而后service1调用service2完成自身业务。至此,完成所有组件贯穿。

       架构中application与sevice的区别是什么?

  1. ​ service提供了基础服务功能;application组装基础服务功能,提供给用户直接可用的业务。
  2. ​ service服务粒度小、功能基础,不易发生改变;application提供上游业务功能,紧贴业务需求,容易发生改变。
  3. ​ 形成service支撑application的整体架构,增加多变的application甚至不需要变动service。

5.4.2、工程结构说明

       采用maven工程,结构如下:

nacos‐micro‐service 整体父工程 
├─api‐gateway API网关,端口:56010 
├─application‐1 应用1,端口:56020 
├─service‐1 服务1父工程 
	│ ├─service‐1‐api 服务1API 
	│ |─service‐1‐server 服务1实现,端口:56030 
|─service‐2 服务2父工程 
	| ├─service‐2‐api 服务2API 
	| |─service‐2‐server 服务2实现,端口:56040

5.4.3、创建父工程

       创建 artifactId 名为 nacos-micro-service 的 Maven 工程,此父工程继承nacos-discovery父工程,间接指定了Spring boot、spring cloud 以及spring-cloud-alibaba的依赖版本。

5.4.4、实现application1

       application1属于应用层,提供http接口服务。

       (1)初始化 application-1 Maven 工程,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>nacos-micro-service</artifactId>
        <groupId>com.ygl.nacos</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>application-1</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.ygl.nacos</groupId>
            <artifactId>service-1-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-dubbo</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.4.4</version>
            </plugin>
        </plugins>
    </build>
</project>

       (2)实现application-1功能

@RestController
public class ApplicationController {

    //注入service(基于dubbo协议)

    @GetMapping("/service")
    public String service() {
        
        return "test";
    }

}

       (3)application1 配置

       定义bootstrap.yml,代码如下所示:

server:
  port: 56020
  servlet:
    context-path: /application1 # 根路径

spring:
  application:
    name: application1
  main:
    allow-bean-definition-overriding: true # 防止bean重复
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: b6cb281f-df22-4f43-9048-ff16ebcdec65
        cluster-name: DEFAULT
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yaml
        namespace: b6cb281f-df22-4f43-9048-ff16ebcdec65
        group: NACOS_MICROSERVICE_GROUP

       (4) application1 启动

启动代码如下:


package com.ygl.microservice;

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

/**
 * TODO
 *
 * @author ygl
 * @version V1.0
 * @since 2021-05-14 15:32
 **/
@SpringBootApplication
@EnableDiscoveryClient
public class Application1Bootstrap {

    public static void main(String[] args) {

        SpringApplication.run(Application1Bootstrap.class, args);
    }

}

       当 Service1Bootstrap 启动后,应用 application1 将出现在 Nacos 控制台界面。

5.4.5、实现Service1

       1、定义service1父工程,pom.xml代码如下:

<parent>
    <artifactId>nacos-micro-service</artifactId>
    <groupId>com.ygl.nacos</groupId>
    <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

       2、定义service-1-api

为了方便其它服务调用dubbo服务,专门定义api工程,此工程将作为jar被其它工程依赖。

       定义service-1-api工程,pom.xml如下:

<parent>
    <artifactId>service-1</artifactId>
    <groupId>com.ygl.nacos</groupId>
    <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service-1-api</artifactId>

       定义服务接口:

public interface ConsumerService {
    public String service();
}

5.4.6、实现service-1-server

       1、初始化service-1-server Maven工程

       添加Maven相关依赖,代码如下:

<dependencies>
        <dependency>
            <groupId>com.ygl.nacos</groupId>
            <artifactId>service-2-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.ygl.nacos</groupId>
            <artifactId>service-1-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-dubbo</artifactId>
        </dependency>
    </dependencies>

       2、实现Dubbo服务

//注意这个注解是Dubbo的Service注解,不是springframework的Service注解
@Service
public class ConsumerServiceImpl implements ConsumerService {

    /**
     * 实现service接口(dubbo接口实现内容)
     * TODO
     *
     * @param
     * @return String
     * @author ygl
     * @date 2021/5/14 15:46
     **/
    @Override
    public String service() {

        return "Consumer invoke ";
    }

}

注意:Service注解是Dubbo的注解,千万不要给导错成springframework包下的注解了。

       3、配置Dubbo服务

       Service2 作为Dubbo服务消费方配置与服务提供方类似,注意,service1不仅是消费方,同时还是服务提供方:

       service1的yml配置文件如下所示:

server:
  port: ${port:56030}

spring:
  application:
    name: service1
  main:
    allow-bean-definition-overriding: true
  cloud:
    nacos:
      discovery:
        cluster-name: DEFAULT
        server-addr: 127.0.0.1:8848
        namespace: b6cb281f-df22-4f43-9048-ff16ebcdec65
      config:
        server-addr: 49.235.125.139:8848
        file-extension: yaml
        namespace: b6cb281f-df22-4f43-9048-ff16ebcdec65

dubbo:
  scan:
    # dubbo 服务扫描基准包
    base-packages: com.ygl.microservice
  protocol:
    # dubbo 协议
    name: dubbo
    # dubbo 协议端口
    port: ${dubbo_port:20881}
  registry:
    address: nacos://127.0.0.1:8848
  application:
    # dubbo 运维服务是否开启
    qos-enable: false
  consumer:
    # 启动时是否检查依赖的服务
    check: false

以上yaml文件中,dubbo开头的为dubbo服务的配置:

  1. dubbo.scan.base-packages :指定Dubbo服务实现类的扫描基准包,将Dubbo包下的@Service注解标注的service暴露为Dubbo服务。
  2. dubbo.protocol :Dubbo服务暴露的协议配置,其中子属性name为协议名称,port为dubbo协议端口号。
  3. dubbo.registry:Dubbo服务注册中心配置,其中子属性address的值为nacos://127.0.0.1:8848,说明dubbo服务注册到nacos中。

yaml文件的上半部分配置为SpringCloud的相关配置:

  1. spring.application.name:Spring应用名称,用于Spring Cloud服务注册和发现;该值在Dubbo Spring Cloud加持下被视作dubbo.application.name,因此无需再配置dubbo.application.name
  2. spring.cloud.nacos.config:Nacos 配置中心配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口。
  3. spring.cloud.nacos.discovery:Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口 。

4、启动服务消费方应用


package com.ygl.microservice.service1;

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

/**
 * TODO
 *
 * @author ygl
 * @version V1.0
 * @since 2021-05-14 15:59
 **/
@SpringBootApplication
@EnableDiscoveryClient
public class Service1Bootstrap {

    public static void main(String[] args) {

        SpringApplication.run(Service1Bootstrap.class,args);
    }
}

       当Service1Bootstrap启动后,应用service1将出现在nacos控制台的服务列表中。

       启动成功,观察服务列表,如下图所示:

image-20210521091748936

5.4.7、实现application1远程调用service1

       现在service1已经暴露dubbo服务,并且注册到nacos中,下面实现application1调用service1

       1、引用service1

       在application1中引用service1

       首先在pom.xml中引用service1-api的依赖

<dependency>
    <groupId>com.ygl.nacos</groupId>
    <artifactId>service-1-api</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

       引用spring-cloud-starter-dubbo依赖,它会根据接口生成代理对象,代码如下:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>

2、实现远程调用


package com.ygl.microservice.application1.controller;

import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import com.ygl.microservice.service1.api.ConsumerService;


/**
 * TODO
 *
 * @author ygl
 * @version V1.0
 * @since 2021-05-14 15:09
 **/
@RestController
public class ApplicationController {

    //注入service(基于dubbo协议)
    @Reference
    ConsumerService consumerService;

    @GetMapping("/service")
    public String service() {

        String service = consumerService.service();
        return "test"+";远程调用service1:"+service;
    }

}

       注意: 这里的注解@Referenceorg.apache.dubbo.config.annotation包下的

       测试:

       请求:http://127.0.0.1:56020/application1/service

       consumerService生成代理对象,service1被调用。

5.4.8、实现service2

       如上面设计所示,Service2需要暴露dubbo接口以供service1消费,若想在Spring cloud Alibaba中集成并使用dubbo。

1、定义父工程

       定义service2父工程,pom.xml代码如下:

<parent>
    <artifactId>nacos-micro-service</artifactId>
    <groupId>com.ygl.nacos</groupId>
    <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

2、定义service-2-api

       定义service-2-api工程,pom.xml如下:

<parent>
    <artifactId>service-2</artifactId>
    <groupId>com.ygl.nacos</groupId>
    <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

       并定义服务接口,Dubbo 服务接口是服务提供方与消费方的远程通讯契约,通常由普通的 Java 接口(interface)来声明,如 ProviderService 接口:


package com.ygl.microservice.service2.api;

/**
 * TODO
 *
 * @author ygl
 * @version V1.0
 * @since 2021-05-14 17:11
 **/
public interface ProviderService {
    String service();
}

3、实现service-2-server

​        3.1、初始化service-2-server的Maven工程

​        首先,创建artifactId名为service-2-server的Maven工程,并在pom.xml中引入Dubbo Spring Cloud必要依赖

<?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>service-2</artifactId>
        <groupId>com.ygl.nacos</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service-2-server</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.ygl.nacos</groupId>
            <artifactId>service-2-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-dubbo</artifactId>
        </dependency>
    </dependencies>
</project>

       以上依赖说明:

  • service-2-api:提供service-2-apiProviderServic接口
  • spring-cloud-starter-dubbo:提供dubbo依赖
  • spring-cloud-starter-alibaba-nacos-discovery:提供nacos的服务注册和发现功能

3.2、实现dubbo服务

       ProvicerService作为暴露的Dubbo服务接口,服务提供方需要service-2-server需要将其实现:


package com.ygl.microservice.service2.service.impl;

import org.apache.dubbo.config.annotation.Service;

import com.ygl.microservice.service2.api.ProviderService;

/**
 * TODO
 *
 * @author ygl
 * @version V1.0
 * @since 2021-05-14 17:15
 **/
@Service
public class ProvicerServiceImpl implements ProviderService {

    @Override
    public String service() {

        return "Provider invoke";
    }

}

       其中@Service注解是Dubbo服务注解,仅声名该java服务实现为Dubbo服务,因此下一步需要将其配置Dubbo服务。

3.3、配置Dubbo服务

       在暴露 Dubbo 服务方面,推荐开发人员外部化配置的方式,即指定 Java 服务实现类的扫描基准包。

Dubbo Spring Cloud 继承了 Dubbo Spring Boot 的外部化配置特性,也可以通过标注

@DubboComponentScan来实现基准包扫描

       同时,Dubbo 远程服务需要暴露网络端口,并设定通讯协议,完整的 YAML 配置如下所示:

server:
  port: ${port:56040}
spring:
  application:
    name: service2
  main:
    allow-bean-definition-overriding: true
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: b6cb281f-df22-4f43-9048-ff16ebcdec65
        cluster-name: DEFAULT
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yaml
        namespace: b6cb281f-df22-4f43-9048-ff16ebcdec65
dubbo:
  scan:
    base-packages: com.ygl.microservice
  protocol:
    port: ${dubbo_port:20891}
    name: dubbo
  registry:
    address: nacos://127.0.0.1:8848
  application:
    # dubbo 运维服务是否开启
    qos-enable: false
  consumer:
    # 启动时是否检查依赖的服务
    check: false

启动服务提供方应用

       Dubbo Spring Cloud 引导类与普通 Spring Cloud 应用并无差别,如下所示:


package com.ygl.microservice.service2.service;

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

/**
 * TODO
 *
 * @author ygl
 * @version V1.0
 * @since 2021-05-14 17:23
 **/
@SpringBootApplication
@EnableDiscoveryClient
public class Service2Bootstrap {

    public static void main(String[] args) {

        SpringApplication.run(Service2Bootstrap.class,args);
    }
}

       在Service2Bootstrap启动之前,记得开启Nacos服务器,当Service2Bootstrap启动之后,应用service2将出现在Nacos控制台界面。

5.4.9、实现service1调用service2

       引用service2

       在service-1-server中添加service-2-api依赖

<dependency>
    <groupId>com.ygl.nacos</groupId>
    <artifactId>service-2-api</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

实现远程调用

       代码如下所示:


package com.ygl.microservice.service1.service;


import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service;

import com.ygl.microservice.service1.api.ConsumerService;
import com.ygl.microservice.service2.api.ProviderService;

/**
 * TODO
 *
 * @author ygl
 * @version V1.0
 * @since 2021-05-14 15:45
 **/

//注意这个注解是Dubbo的Service注解,不是springframework的Service注解
@Service
public class ConsumerServiceImpl implements ConsumerService {

    @Reference
    ProviderService providerService;

    /**
     * 实现service接口(dubbo接口实现内容)
     * TODO
     *
     * @param
     * @return String
     * @author ygl
     * @date 2021/5/14 15:46
     **/
    @Override
    public String service() {

        String service = providerService.service();
        return "Consumer invoke "+";service1远程调用service2:"+service;
    }

}

测试:

       请求地址:127.0.0.1:56020/application1/service

       application1项目调用service1项目;service1项目调用service2项目

5.4.10、实现api-gateway

       1、网关介绍

       什么是网关?

              原来的单体架构,所有的服务都是本地的,UI可以直接调用,现在按功能拆分成独立的服务,跑在独立的一般都在独立的虚拟机上的 Java进程了。客户端UI如何访问?他的后台有N个服务,前台就需要记住管理N个服务,一个服务下线/更新/升级,前台就要重新部署,这明显不服务我们拆分的理念,特别当前台是移动应用的时候,通常业务变化的节奏更快。另外,N个小服务的调用也是一个不小的网络开销。

       有了网关作为服务统一入口,就可以避免上述问题,不仅如此,服务网关是在微服务前边设置一道屏障,请求先到服务网关,网关会对请求进行过虑、校验、路由等处理。有了服务网关可以提高微服务的安全性,网关校验请求的合法性,请求不合法将被拦截,拒绝访问。

  • 提供统一服务入口,让微服务对前台透明
  • 聚合后台的服务,节省流量,提升性能
  • 提供安全,过滤,流控等API管理功能

什么是Zuul?

       Spring Cloud Zuul是整合Netflflix公司的Zuul开源项目实现的微服务网关,它实现了请求路由、负载均衡、校验过虑等 功能。

Zuul与Nginx怎么配合使用?

       Zuul与Nginx在实际项目中需要配合使用,如下图,Nginx的作用是反向代理、负载均衡,Zuul的作用是保障微服务的安全访问,拦截微服务请求,校验合法性及负载均衡。
image-20210524173515767
搭建网关工程

       初始化api-gateway Maven工程,代码如下:

<dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>

api-gateway配置

server:
  port: 56010

spring:
  application:
    name: api-gateway
  main:
    allow-bean-definition-overriding: true
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: b6cb281f-df22-4f43-9048-ff16ebcdec65
        cluster-name: DEFAULT
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yaml
        namespace: b6cb281f-df22-4f43-9048-ff16ebcdec65
        group: NACOS_MICROSERVICE_GROUP

       网关的路由配置采用nacos远程配置,在nacos控制台开发环境中新增api-gateway.yaml配置集,配置组为 TEST_GROUP,配置内容如下:

zuul: 
	routes: 
		application1: 
			stripPrefix: false 
			path: /application1/**

       将请求为 /application1/ 开头的请求路由至 application1 服务

api-gateway启动

       注意在启动类上使用@EnableZuulProxy注解标识此工程为Zuul网关,启动类代码如下:


package com.ygl.microservice.gateway;

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

/**
 * TODO
 *
 * @author ygl
 * @version V1.0
 * @since 2021-05-14 18:27
 **/
@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
public class ApiGatewayBootstrap {

    public static void main(String[] args) {

        SpringApplication.run(ApiGatewayBootstrap.class, args);
    }

}

       当 Service1Bootstrap 启动后,应用 api-gateway 将出现在 Nacos 服务列表中。

       通过网关(api-gateway)请求Application1应用,Application1的业务实现又贯穿service1、service2,访问

       http://127.0.0.1:56010/application1/service ,将得到如下结果:

image-20210524175314189

       源码地址:https://github.com/ygl01/nacos.git

       这个源码里有三个不同的父项目,大家注意区分,而且记得更改nacos服务器地址。

       好了,今天的分享就到这吧,今天这篇分享的nacos的配置中心和服务注册与发现中心。

       那些有分享的不对的地方,还恳请大家能够指正哦。

       大家记得一键三连哦,转发 点赞 评论。

       我就是小y;我们下期见。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐