Dubbo基础专题——第四章(Dubbo整合Nacos分析细节点)

Posted 皮卡皮卡程序员

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dubbo基础专题——第四章(Dubbo整合Nacos分析细节点)相关的知识,希望对你有一定的参考价值。

应广大的读者要求,也是公司目前需要一些支持,我就自己亲身搭建一个Springboot+nacos+dubbo的框架和项目,并演示dubbo面对一些系统的

业务场合,应该怎么去做支持,文章中我会先贴出代码地址,如果不需要仔细的学习,那么直接下载地址就好了,

如果想跟着学为什么要这么玩,那么请耐心的往下看,我会用很简单的语言,来诠释很多概念和你们在搭建的时候,会遇到的一些问题,这些问题应

该怎么处理,产生的原因是什么,好了废话不多说,开始了!!

1、环境搭建

idea版本,你随便

jdk版本,1.8+以上

代码地址:https://gitee.com/cx_gitee/springboot-nacos-dubbo.git

首先我新建一个父工程

然后写你的groupId和artifictId,你可以不按照我这么写,如果你对maven熟悉的话

然后选择路径

创建好后,你把src删除掉,结构是这样的

然后再建立几个子工程,我只举一个例子,剩下的自己创建哈!

然后新建还是maven项目

创建一个用户服务

然后finish,src就别给我删了啊。。。

创建user服务对外暴露的api项目,叫做user-provider-api

生产者部分已经创建完了,接着创建消费者,订单服务order-consumer,负责调用生产者user,获取用户信息;

重复上面的步骤,是这样的

好,接下来我们先做依赖关系,我们本章的要求是搭建一个Springboot+nacos+dubbo,

我默认读者是已经了解过这些技术,但是需要一个比较完整的环境;

nacos是阿里的产品,本章我目前只用来做个注册中心,配置中心的用法我后面说

dubbo看我前两章节,写的比较清楚

首先这个依赖管理,我要让springboot-nacos-dubbo这个父类管理依赖,所以我要让项目的父pom继承springboot的parent;

pom

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.9.RELEASE</version>
        <relativePath/>
    </parent>

这样就表明我这个项目,已经从maven迈进springboot的第一步。

然后这个父pom要管理依赖关系

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud-alibaba.version>2.1.1.RELEASE</spring-cloud-alibaba.version>
        <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
        <dubbo.version>2.7.3</dubbo.version>
    </properties>

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

            <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>org.apache.dubbo</groupId>
                <artifactId>dubbo-spring-boot-starter</artifactId>
                <version>${dubbo.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

截图说明下,既然是nacos,就从属于Alibaba微服务系列,需要建立个版本约定进来,子项目你用不用那另说;

既然springboot要整合dubbo,就要有整合的场景驱动器dubbo-spring-boot-starter

那么springcloud依赖为什么要引进来呢,其实这个我也说不好,官网的demo案例就这么干的:

看依赖截图:

所以对于user-provider来说,pom是这样的:

    <dependencies>
        <!--    springboot web相关    -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
        </dependency>

        <!--nacos注册中心 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!--nacos配置中心 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
    </dependencies>

2、开始编码

用户服务要拿用户信息,我们在user-provider-api中写实体和接口,原因我上一节已经说明,因为在实体,接口,都会被其他服务所引用;

所以我们要编写用户实体,用户接口类

public class User {

    private Integer id;

    private String username;

    public User(Integer id, String username) {
        this.id = id;
        this.username = username;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
}

UserService接口

public interface UserService {

    User getUserInfo(Integer id);
}

整体的截图是这样的:

接口实体都有了,那么可以在服务中暴露接口+业务逻辑了,前提user-provider的依赖要把user-provider-api引入进来,记得要把api install到本地,不然找不到!

那么这个时候,是不是少了一个主启动类?不然你怎么启动你的user-provider?

注意你的目录级别,主启动类建议以这样的方式走,知道Springboot的就知道刚创建出来的项目结构就是这样的;@EnableDubbo这个注解是开启注解配置dubbo;

然后我们要配置application.yml和bootstrap.yml,这两者区别是:

bootstrap 里面的属性在springboot项目启动的时候,会优先加载,对于nacos来说,建议配置在bootstrap中

在resource下新建两个文件,application.yml和bootstrap.yml

bootstrap.yml

spring:
  cloud:
    nacos:
      config:
        enabled: false
        server-addr: 127.0.0.1:8848
      discovery:
        server-addr: 127.0.0.1:8848

application.yml

server:
  port: 8081


spring:
  application:
    name: user-provider

dubbo:
  consumer:
    check: false
  application:
    name: ${spring.application.name}
  protocol:
    port: 20881
    name: dubbo
  registry:
    address: nacos://127.0.0.1:8848

这些属性的意思我后面收尾介绍,先搭建起来

我们用nacos是本地的,所以可以下载版本下来,windows版本地址是:https://github.com/alibaba/nacos/releases/download/1.3.2/nacos-server-1.3.2.zip

然后本地解压后启动nacos,进入nacos的bin目录,以单机模式启动;

默认是8848端口,输入地址:http://localhost:8848/nacos

登陆名和密码都是nacos

这样nacos就启动成功了!!!

于是我们启动user-provider服务

在nacos注册中心上会有两行,第一行就是你的服务要被nacos发现,注册上你服务的信息,第二行是provider:com....,很明显,是你暴露的服务名,因为你的UserServiceImpl加了@Service注解,那么dubbo就会把你的服务暴露在注册中心!!

那么提供者我们已经做好了,该消费端order-service了,其实步骤和上面差不多,我主要写些不同之处

api中

service:

同样我在order服务中我要调用user服务,需要写个controller,里面要远程调用UserService接口,所以别忘记在order-consumer这个服务中pom要引入user-provider-api的依赖!!!这些我其实都不想说了,但是为了初学者可以看懂,我也拼了。。。

紧接着你肯定要把你暴露接口的实现也要写下

差个主启动类,注意层级关系

同样bootstrap和application复制一份进来,但是记得有些地方要改改

bootstrap.yml不变,和生产者一样;

application.yml,注意端口变了,user服务的端口是8081,order是8080,还有服务名也要改变,还有就是dubbo协议发起的端口,user是20881,order是20880,一个服务一个协议端口,这点要记清楚!!不然端口冲突

server:
  port: 8080


spring:
  application:
    name: order-consumer

dubbo:
  consumer:
    check: false
  application:
    name: ${spring.application.name}
  protocol:
    port: 20880
    name: dubbo
  registry:
    address: nacos://127.0.0.1:8848

然后我们要启动消费者,启动成功;

看下nacos,多出来两个,下面一个是消费者服务,上面一个是因为加了远程调用的注解@Reference,产生了consumer:com....,会告诉注册中心,我消费者服务也要去 注册中心上找提供者。

有人会有疑惑,我作为消费者,我只需要从注册中心找就可以了,为啥要把自己注册到注册中心呢?应该是有这个疑问的吧?

当然不是,如果作为消费者,你的服务不让注册中心知道,你连门都进不去,你怎么去要这栋大楼的花名册?进来至少要登记你的信息,后面你消费者存不存在了,注册中心也需要感知,怎么感知呢,所以你也要注册上注册中心。

所以我们调用接口地址:localhost:8080/getOrder

哦豁,报错了,看我标记,dubbo中传输数据,需要序列化和反序列化,所以你所有的实体都应该实现Serializable接口,这里记得改下!!!!

当把所有的实体都加上序列化后,

两个服务都重启后,调用结果是:

控制台已经打印,说明已经调用成功!!!

那么简单的消费者和生产者我就演示到这,我接下来说下配置文件的事情!!

来看配置文件,先看bootstrap

spring.cloud.nacos.config.enable: false 表示是否开启配置中心?因为nacos既可以用做注册中心,也可以作为配置中心;这里我们只用来做注册中心,后面的server-addr是表示配置中心的地址,关闭不开启,写不写都可以

所以重点关注spring.cloud.nacos.discovery  表示服务注册发现,也就是注册中心地址,因为默认的enable属性是true,默认开启注册中心,所以写个地址就好

还是那句话,我们建议nacos注册中心的服务发现配置,配置在bootstrap里面!!!

spring:
  cloud:
    nacos:
      config:
        enabled: false
        server-addr: 127.0.0.1:8848
      discovery:
        server-addr: 127.0.0.1:8848

来看application

端口不说了,application.name 也不说了,重点看dubbo的标签

dubbo.consumer.check 这个代表你作为消费者,启动的时候是不是需要检查生产者是否存在?如果生产者不存在,会提示no Provider,重试3次后,消费者发现不到生产者,是无法启动的,所以为了避免这个情况

我们把这个值设置为false,表示启动的时候不检查,等到调用的时候,再去检查是否生产者存在,从而完成远程调用逻辑。建议关闭

protocol表示dubbo协议的相关内容,前面章节我说到dubbo是一种rpc框架,也是基于tcp连接,既然是网络传输,就要有自己的协议,也要对应的端口,不然你这个请求到哪里去嘛?

dubbo.registry表示dubbo注册中心的配置,用来配置连接注册中心相关的信息。因为dubbo的服务,要上注册中心,所以这里配置nacos的注册中心地址。

server:
  port: 8080


spring:
  application:
    name: order-consumer

dubbo:
  consumer:
    check: false
  application:
    name: ${spring.application.name}
  protocol:
    port: 20880
    name: dubbo
  registry:
    address: nacos://127.0.0.1:8848

简单的配置,我就介绍到这里,接下来重点来了。

有很多读者都问,微服务公司就是这么玩的吗?

回答并不是,这是最入门最初级的,但是很多行业内的人,连入门都达不到,连配置的策略都不清楚,模模糊糊的,那是不行的,最起码你要能说服你自己。

那么当你在面对不同的系统,不同的模块,要进行整体的架构更换,仅仅这点知识,是完全不够的,下面我就讲述,在实际开发中会遇到的一些点,dubbo怎么处理的!!

3、开发常见的问题

还是以这两个服务为例子

user-provider

order-consumer

调用关系是,order-consumer订单服务调用user-provider用户服务

如果我此时此刻,新增一个服务,这个服务叫做pay-provider支付服务,再新增一个存储的接口storage-api + storage-service服务,在storage-api里面既有service,又有实现类;

如下图,如果storage-api只有接口,实现类在storage-service中,我们只需要把storage-service注册上nacos就可以了。

但是如果storage-api中有默认的实现,那么user-provider和pay-provider中,该怎么暴露storage-api的接口呢?

建立的storage-api里面随便写个service和默认的实现类,这样的业务场景是很常见的,很多服务会引入这个底层storage-api包,可以使用默认实现类,也可以重写默认实现,根据自己的需求来定

那假如目前user-provider服务和pay-provider服务,都要使用这个存储,对于一个任意一个消费者我想调用你们暴露的存储接口,应该怎么做?

首先我要在user-provider服务和pay-provider服务的pom中引入这个存储的api:

光引用不行,我的需求现在是,很多服务都有这个基础包storage-api,里面有默认的实现类,对于模块来说,我不想用他的默认实现,我想自己重写实现,暴露我重写后的服务怎么办?

这样就可以了,

启动两个服务user-provider服务和pay-provider服务,pay-provider配置和user-provider一样,注意dubbo协议端口和服务的端口+服务名字!!

很明显看到,pay已经注册上去,并且provider StorageService有两个实例,很明显是来自两个不同的服务,不信你可以点击详情看下里面的内容

点击详情:

此时我有一个消费者,假设就拿上面的order-consumer,你说我要调用不同服务暴露的接口,应该怎么实现???

启动消费者,调用localhost:8080/getStorage 这个请求很多次,我们看是怎么样的一个调用方式?控制台打印的是哪个服务里面的??我们看下

结果发现两个服务都被调用了,并且你看,我点了7次,一边3一边4,其实dubbo默认是负载轮询调用,尽管是这样;这不是我们想要的效果啊~~~我想调用user-provider暴露自己写的storage接口实现的怎么办?

很简单,dubbo提供了分组策略,我只需要在不同的服务暴露的接口中,加个分组就可以

在调用方我只要指定调用的服务属于那个组就可以了!这样就可以确保调用方调用对应暴露的接口了!!

大概就先说到这,后面坑点我继续补充,代码的地址我放在git上了,感兴趣可以下载下来看看哈,多谢支持!!!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

以上是关于Dubbo基础专题——第四章(Dubbo整合Nacos分析细节点)的主要内容,如果未能解决你的问题,请参考以下文章

深入浅出Sentinel原理及实战「框架整合专题」Sentinel服务框架对接Dubbo服务框架整合开发指南

Dubbo 专题(基础篇):Dubbo 介绍环境搭建与实践

Dubbo 专题(基础篇):Dubbo 介绍环境搭建与实践

Dubbo 专题(基础篇):Dubbo 介绍环境搭建与实践

Dubbo 专题(基础篇):Dubbo 介绍环境搭建与实践

Dubbo基础专题——第二章(Dubbo工程简单实践)