• 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

    
    <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.0modelVersion>
    
        <groupId>wu.examplegroupId>
        <artifactId>dubbo_wu_demoartifactId>
        <version>${project.version}version>
    	<packaging>pompackaging>
    	
        <properties>
            <project.version>1.0.0-SNAPSHOTproject.version>
            <java.version>1.8java.version>
            <maven.version>3.8.1maven.version>
            <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
            <spring-boot.version>2.3.7.RELEASEspring-boot.version>
            <dubbo.version>3.1.2dubbo.version>
        properties>
    
        <modules>
            <module>user-servermodule>
            <module>order-servermodule>
        modules>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-dependenciesartifactId>
                    <version>${spring-boot.version}version>
                    <type>pomtype>
                    <scope>importscope>
                dependency>
                <dependency>
                    <groupId>org.apache.dubbogroupId>
                    <artifactId>dubbo-spring-boot-starterartifactId>
                    <version>${dubbo.version}version>
                dependency>
                <dependency>
                    <groupId>org.apache.dubbogroupId>
                    <artifactId>dubbo-dependencies-zookeeperartifactId>
                    <version>${dubbo.version}version>
                    <type>pomtype>
                dependency>
            dependencies>
        dependencyManagement>
    
        <build>
            
            <resources>
                <resource>
                    <directory>src/main/javadirectory>
                    <includes>
                        <include>**/*.propertiesinclude>
                        <include>**/*.xmlinclude>
                    includes>
                    <filtering>falsefiltering>
                resource>
            resources>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.pluginsgroupId>
                    <artifactId>maven-compiler-pluginartifactId>
                    <version>${maven.version}version>
                    <configuration>
                        <source>${java.version}source>
                        <target>${java.version}target>
                        <encoding>UTF-8encoding>
                    configuration>
                plugin>
                
                <plugin>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-maven-pluginartifactId>
                    <version>${spring-boot.version}version>
                    <executions>
                        <execution>
                            <goals>
                                
                                <goal>repackagegoal>
                            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依赖,因为在父项目中已经声明过版本了,所以子项目中就不用在书写版本号了

    
    <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_demoartifactId>
            <groupId>wu.examplegroupId>
            <version>1.0.0-SNAPSHOTversion>
        parent>
    
        <modelVersion>4.0.0modelVersion>
        <artifactId>user-serverartifactId>
        <version>${parent.version}version>
        <name>user-servername>
    
        <dependencies>
            
            <dependency>
                <groupId>org.apache.dubbogroupId>
                <artifactId>dubbo-spring-boot-starterartifactId>
            dependency>
    
            
            <dependency>
                <groupId>org.apache.dubbogroupId>
                <artifactId>dubbo-dependencies-zookeeperartifactId>
                <type>pomtype>
                <exclusions>
                    <exclusion>
                        <groupId>org.slf4jgroupId>
                        <artifactId>slf4j-log4j12artifactId>
                    exclusion>
                exclusions>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
                <scope>testscope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintagegroupId>
                        <artifactId>junit-vintage-engineartifactId>
                    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如下所示

    
    <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_demoartifactId>
            <groupId>wu.examplegroupId>
            <version>1.0.0-SNAPSHOTversion>
        parent>
    
        <modelVersion>4.0.0modelVersion>
        <artifactId>order-serverartifactId>
        <version>${parent.version}version>
        <name>order-servername>
    
        <dependencies>
            
            <dependency>
                <groupId>org.apache.dubbogroupId>
                <artifactId>dubbo-spring-boot-starterartifactId>
            dependency>
    
            
            <dependency>
                <groupId>org.apache.dubbogroupId>
                <artifactId>dubbo-dependencies-zookeeperartifactId>
                <type>pomtype>
                <exclusions>
                    <exclusion>
                        <groupId>org.slf4jgroupId>
                        <artifactId>slf4j-log4j12artifactId>
                    exclusion>
                exclusions>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
                <scope>testscope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintagegroupId>
                        <artifactId>junit-vintage-engineartifactId>
                    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接口,声明接口方法

    在这里插入图片描述

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

    
    <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_demoartifactId>
            <groupId>wu.examplegroupId>
            <version>1.0.0-SNAPSHOTversion>
        parent>
    
        <modelVersion>4.0.0modelVersion>
        <artifactId>service-apiartifactId>
        <version>${parent.version}version>
        <name>user-servername>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-maven-pluginartifactId>
                    <configuration>
                        <skip>trueskip>
                        <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

    
                wu.example
                service-api
                ${parent.version}
    
    
    • 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来做一层代理。后续我们一一
    演示

  • 相关阅读:
    【华为机试真题 JAVA】最大嵌套括号深度-100
    c++中类的默认成员函数
    Nature Communications | 张阳实验室:端到端深度学习实现高精度RNA结构预测
    Rust中的单元测试
    swift 函数类型+高阶函数
    火热的低代码,是时候系统的来学一学了!
    PTA题目 A除以B
    【监听服务器】自动重启脚本
    【NodeJs-5天学习】第四天存储篇③ ——基于物联网的WiFi自动打卡考勤系统,升级存储为mysql,提醒功能改为QQ
    Python装饰器进阶:深入理解与最佳实践
  • 原文地址:https://blog.csdn.net/qq_24950043/article/details/127914149