当前位置:   article > 正文

dubbo:从零理解及搭建dubbo微服务框架(一)【附带源码】

dubbo

0.引言

dubbo作为阿里巴巴开源的微服务框架,提供了高性能的RPC调用。同时因为有阿里的背书,在国内市场得到了广泛应用,dubbo的开源工作在2018年2月阿里将项目捐献给apache基金会后,得到了更加广大的发展。

之前我们讲解了springcloud微服务体系的入门学习,今天同样带大家来快速入门掌握dubbo微服务框架的应用,让大家逐步了解springcloud alibaba体系

1. 概念

1.1 什么是dubbo?

首先大家要了解到底什么是dubbo,他是一个组件,还是一门语言?实际上dubbo一个服务框架,一开始是用java编写,后续产生了go语言版本。因为dubbo本身自带了RPC调用功能,也就是组间调用。所以也称dubbo为RPC服务框架

我们来看官方对于dubbo的定义:

dubbo官方文档

Apache Dubbo 是一款 RPC 服务开发框架,用于解决微服务架构下的服务治理与通信问题,官方提供了 Java、Golang 等多语言 SDK 实现。使用 Dubbo 开发的微服务原生具备相互之间的远程地址发现与通信能力, 利用 Dubbo 提供的丰富服务治理特性,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。Dubbo 被设计为高度可扩展,用户可以方便的实现流量拦截、选址的各种定制逻辑。

Dubbo3 定义为面向云原生的下一代 RPC 服务框架。3.0 基于 Dubbo 2.x 演进而来,在保持原有核心功能特性的同时, Dubbo3 在易用性、超大规模微服务实践、云原生基础设施适配、安全性等几大方向上进行了全面升级。

对于初学者,看起来是不是觉得晦涩难懂,但实际上大家要抓住核心词:服务治理服务通信。这是dubbo框架所提供的核心功能。实际上也是微服务框架所要提供的核心功能。

以前我们讲解过什么是微服务。那么实际上微服务要解决的两个核心问题就是服务治理与通信。

1.1.1 服务治理

服务治理是什么,就是服务的发现与分发,也就是管理有哪些种类的服务、每个种类的服务有多少个实例(可以简单理解为服务实际部署了多少台服务器),再次简化,就是如下的这张表格:

服务名ip
user-server 用户服务192.168.101.1
user-server 用户服务192.168.101.2
user-server 用户服务192.168.101.3
order-server 订单服务192.168.101.4
order-server 订单服务192.168.101.5
order-server 订单服务192.168.101.6

我们有处理用户信息的用户服务,部署了3台服务器,还有处理订单信息的订单服务,同样部署了3台。那么当用户在我们的网站上发起请求时,比如做了一个下单操作。

那么我的流程是要先获取这个用户的用户信息,也就要调用到用户服务,然后再创建订单,也就需要订单服务。那么用户肯定不会知道我们有多个用户服务和订单服务的,也不会知道我们部署这个服务的Ip地址。所以就需要一个东西管理这些服务,将用户的请求自动转发到对应的服务所对应的服务器上。

这样一个操作就是服务治理

在这里插入图片描述

好了,再回到一开始的概念,我们前面说dubbo是服务框架,记住它不是组件,框架是结合具体的项目一起使用的,组件是可以单独部署的。

一般dubbo常常和zookeeper结合来实现服务治理,也就是用zk来做注册中心。如果不了解注册中心概念的,请先阅读上面列举的《什么是微服务》。

我们再说的直白一点,dubbo具体到java项目中,就是我们引入的一个jar包,我们只需要简单的引用,以及配置文件的配置,dubbo就可以帮助我们将我们的服务注册到zookeeper中,zk充当的就是上述那张表格的实时记录

而这些注册、调用的操作,都不需要我们手动时间,而是通过我们引入的dubbo包来自动实现的,这就是框架。

1.1.2 服务通信

还有一个概念是“服务通信”,也称组间调用,也就是解决服务与服务之间的内部调用。

我们看上述的调用图,订单服务为了获取用户信息,需要调用用户服务,这里做习惯了单机架构的同学可能会疑问,你要获取用户信息,你写一个UserService不就完了嘛,你搞什么幺蛾子还单独开个用户服务,这就要理解微服务的核心概念——专业的事专业的服务去干,用户的信息请让用户服务去管,如果一个服务管的东西太多,不就又回到了单机架构了嘛。

当然如果你服务请求的本身的量就不大,项目的规模也没有那么广,那么自然不需要如此细粒度的服务拆分。

我们知道接口调用,可以通过HttpClient来实现,那么服务间调用的时候为什么不直接用httpclient呢,因为没有部署服务前我们根本都不知道服务的ip或域名,这是注册到注册中心后,注册中心告诉我们的。

当然你说我已经规定好了这个服务就要部署到固定的服务器上,那我可以直接用httpclient调用吗?当然可以了,万变不离其中,这本质上就是一个局域网内的接口调用。但是你想想,这足够灵活吗?

所以dubbo做了一个事情,也就是rpc的含义,让服务间调用,像本地调用一样简单!

什么意思?

就是我们调用用户服务时,只需要引一个UserService,然后按照类的形式来使用即可,但这个Serivice是的实现是定义在用户服务中的,这两个都不在一个项目里面,是怎么做到的呢,我们下面来实际搭建一个dubbo微服务,让大家深入感受一下

1.2 项目简介

开始搭建之前,我们先说明本次演示项目的情况,我们将搭建一个订单服务,在订单服务中调用用户信息,以此来创建订单。

因为要用到注册中心,本次演示我们选用zookeeper,当然dubbo支持的注册中心不止zk,还有nacos与consul。

1.3 消费者与生产者

这里额外补充一点,因为dubbo官方讲解中常提到生产者与消费者的概念,对于初学者来讲会有些陌生。

但实际上这个概念非常好理解,比如我上述订单服务要获取用户信息就需要调用用户服务,那么用户服务就是生产者,因为用户服务要提供用户信息。订单服务要调用用户信息,即消费用户信息,所以订单服务是消费者,当然如果订单服务也需要对别的服务提供信息时,也需要将它注册成消费者。

具体我们进入到项目中来看。

如果你是刚学习微服务的同学,更加建议大家在搭建完dubbo后,系统学习下我之前书写的微服务入门专栏:

从零开始学习微服务

在这里插入图片描述

2. 项目搭建

2.1 下载安装

1、首先需要安装zookeeper,为了演示完整,我这里还额外安装了dubbo-admin,一个官方提供的可以可视化管理dubbo服务的web应用。不知道怎么安装的同学可以参考这篇文章:

docker安装dubbo-admin、zookeeper

2.2 搭建父项目

1、我们需要创建一个maven空项目,作为父项目

在这里插入图片描述

注意这里我将版本号和包名做了调整

在这里插入图片描述

2、该项目下不需要任何目录,删除原有的src目录

在这里插入图片描述

3、修改父项目的pom.xml,统一jar包版本管理,注意这里我已经提前将需要用到的jar包的版本号做了声明,同时将子项目的服务名在modules标签中提前说明了。如果后续有新子项目引入,需要在此标签中添加。还要将父项目的打包方式改为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>wu.example</groupId>
    <artifactId>dubbo_wu_demo</artifactId>
    <version>${project.version}</version>
	<packaging>pom</packaging>
	
    <properties>
        <project.version>1.0.0-SNAPSHOT</project.version>
        <java.version>1.8</java.version>
        <maven.version>3.8.1</maven.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
        <dubbo.version>3.1.2</dubbo.version>
    </properties>

    <modules>
        <module>user-server</module>
        <module>order-server</module>
    </modules>

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

    <build>
        <!--  设置资源目录 -->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven.version}</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <!--   maven打包插件 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <!-- 将依赖的包一起打到jar中-->
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89

2.3 创建用户服务user-server

1、在该项目下右键新建一个子项目

在这里插入图片描述

2、创建用户服务,选择springboot框架,注意将包名调整为与父项目一致

在这里插入图片描述

3、为了演示方便,我们引入spring-web依赖

在这里插入图片描述

4、修改user-server项目的pom,引入dubbo-spring-boot-starter,dubbo-dependencies-zookeeper依赖,因为在父项目中已经声明过版本了,所以子项目中就不用在书写版本号了

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <parent>
        <artifactId>dubbo_wu_demo</artifactId>
        <groupId>wu.example</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <artifactId>user-server</artifactId>
    <version>${parent.version}</version>
    <name>user-server</name>

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

        <!-- Zookeeper dependencies -->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-dependencies-zookeeper</artifactId>
            <type>pom</type>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</project>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

5、同时为了项目的简洁清爽,以及版本的统一管理,我们做一些调整:
(1)删除多余不需要的文件,将.gitignore,README.md挪到父项目下
(2)配置文件格式改为yml(个人更喜欢yml格式,可以根据你的习惯)
在这里插入图片描述

6、创建一个UserServiceImpl类,用来模拟根据用户ID提供用户信息,因为我们需要给订单服务调用,需要被注册为dubbo服务,所以需要使用@DubboService注解


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

/**
 * @author benjamin_5
 * @Description
 * @date 2022/11/19
 */
@DubboService
public class UserServiceImpl {
    
    public String getUserById(Integer id){
        return "用户" + id;
    }
    
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

7、修改配置文件properties.yml

更多的dubbo配置项可参考官方配置项介绍

# 应用名称
dubbo:
  application:
    name: user-server
  protocol: # 指定通信规则
    name: dubbo # 通信协议
    port: -1 # dubbo协议端口,以供消费者访问,-1即为随机端口
  registry: # 注册中心
    id: zk-registry
    address: zookeeper://127.0.0.1:2181

# 应用服务 WEB 访问端口
server:
  port: 8081
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

8、作为生产者,也就是服务的提供者,我们还需要将其启动类上添加@EnableDubbo注解

2.4 创建订单服务order-server

1、创建springboot项目order-server,与user-server引用同样的依赖,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 https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <parent>
        <artifactId>dubbo_wu_demo</artifactId>
        <groupId>wu.example</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <artifactId>order-server</artifactId>
    <version>${parent.version}</version>
    <name>order-server</name>

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

        <!-- Zookeeper dependencies -->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-dependencies-zookeeper</artifactId>
            <type>pom</type>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>


</project>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

2、修改配置文件

# 应用名称
dubbo:
  application:
    name: user-server
  protocol: # 指定通信规则
    name: dubbo # 通信协议
    port: -1 # dubbo协议端口,以供消费者访问,-1即为随机端口
  registry: # 注册中心
    id: zk-registry
    address: zookeeper://127.0.0.1:2181

# 应用服务 WEB 访问端口
server:
  port: 8082
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

3、创建一个接口,用来模拟订单创建,需要在这个接口内调用用户服务的UserServiceImpl,dubbo中引用service需要使用@DubboReference

但问题出现了,我们直接引用是会报错的,那这要怎么操作呢?不是说的像本地调用这么简单吗

在这里插入图片描述

4、毕竟还是在两个服务中,要想纯粹的直接调用肯定出问题,那可以想一想,先不考虑调用的问题,想让一个类能够在另一个服务中调用的方法是什么?

没错,就是引用,当然我们不能直接在order-server中引用user-server,不然要是用户服务也需要调订单服务的话,不就造成循环依赖了吗

5、我们创建一个server-api服务,专门用于存放service接口类

在这里插入图片描述

6、该服务不需要启动类,仅需要创建一个UserService接口,声明接口方法

在这里插入图片描述

项目依赖如下,因为没有启动类,所以要单独调整其打包方式:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <parent>
        <artifactId>dubbo_wu_demo</artifactId>
        <groupId>wu.example</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <artifactId>service-api</artifactId>
    <version>${parent.version}</version>
    <name>user-server</name>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <skip>true</skip>
                    <finalName>${project.name}</finalName>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

同时父项目pom中要把该项目的module加上

在这里插入图片描述

7、创建完成后项目整体mvn install一下,让server-api包存放到本地仓库,方便其他服务引用

在这里插入图片描述

在这里插入图片描述

8、在user-server,order-server中都引入server-api

<dependency>
            <groupId>wu.example</groupId>
            <artifactId>service-api</artifactId>
            <version>${parent.version}</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

9、修改user-server中的UserServiceImpl,让申明UserService接口

@DubboService
public class UserServiceImpl implements UserService {

    @Override
    public String getUserById(Integer id){
        return "用户" + id;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

10、同时order-server中则不再引用UserServiceImpl了,而是引用其接口类

@RestController
public class OrderController {

    @DubboReference
    private UserService userService;

    @GetMapping("createOrder")
    public String createOrder(Integer id){
        String userName = userService.getUserById(id);
        return userName + " createOrder success";
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

所以到这里,大家明白dubbo组间调用的使用方法了吗?

2.5 测试

1、我们将订单服务和用户服务启动起来,注意先启动生产者user-server,再启动生产者order-server

我们使用zk可视化工具prettyZoo,可以看到服务已经注册上去了

在这里插入图片描述

同时也可以用dubbo-admin查看

在这里插入图片描述

这里我们可以看到,只有生产者会注册上去,而消费者只是从注册中心拉取服务

2、调用创建用户的接口

在这里插入图片描述

调用成功!

演示源码

上述演示源码可在如下地址下载:

https://gitee.com/wuhanxue/dubbo_wu_demo

总结

如上,我们针对dubbo框架的简单搭建就完成了, 实际还可以接入gateway来实现网关,或者也可以使用Nginx来做一层代理。后续我们一一
演示

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号