SpringBoot 集成 Dubbo

发布时间 2023-12-30 19:39:50作者: Higurashi-kagome

分布式、微服务与 RPC

什么是分布式?分布式就是将一个应用程序的功能拆分到多个独立的进程中,每个进程都运行在不同的机器上,通过网络连接起来,这样就形成了一个分布式的系统。

什么是微服务架构?微服务架构将应用程序拆分成一组小的服务(微服务),每个服务运行在自己的进程中,服务之间通过轻量级的通信机制互相通信。

什么是 RPC?RPC(Remote Procedure Call)远程过程调用,微服务架构中,服务与服务之间通过网络通信的过程。比如 A 服务调用 B 服务中的方法的过程,就叫 RPC。

什么是 Dubbo

Dubbo 是一款高性能、轻量级的开源 Java RPC 框架。主要解决了微服务之间的通信问题,它提供了一套类似于本地调用的远程调用方式。

Dubbo 架构

Dubbo 架构

角色说明:

  • 服务提供者(Provider):服务提供者就是实现了服务接口的类。服务提供者启动时,向注册中心注册自己提供的服务。
  • 服务消费者(Consumer):服务消费者就是调用远程服务的类。服务消费者启动时,向注册中心订阅自己所需的服务。
  • 注册中心(Registry):注册中心存储服务提供者的地址信息。服务提供者的地址发生变化时,注册中心更新服务提供者地址信息,并通知服务消费者。Dubbo 官方推荐使用 ZooKeeper 作为注册中心。
  • 监控中心(Monitor):监控中心主要用于监控服务的运行状态,以便出现问题时,能及时发现和解决。
  • 容器(Container):服务运行容器,一般就是 Spring 容器。

交互过程说明:

  • 虚线都是异步访问,实线都是同步访问
  • 蓝色虚线:在启动时完成的功能
  • 红色虚线(实线)都是程序运行过程中执行的功能

调用关系说明:

  1. 服务容器负责启动,加载,运行服务提供者。
  2. 服务提供者在启动时,向注册中心注册自己提供的服务。
  3. 服务消费者在启动时,向注册中心订阅自己所需的服务。
  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

示例

安装并启动 Zookeeper

我们用 Zookeeper 作为注册中心,所以先安装并启动 Zookeeper。

安装 Zookeeper:

  1. 安装 JDK(略)
  2. 把 Zookeeper 的压缩包(这里是 zookeeper-3.4.6.tar.gz)上传到 Linux
  3. 解压缩压缩包:tar -zxvf zookeeper-3.4.6.tar.gz,假设解压到/usr/local/zookeeper-3.4.6
  4. 进入 zookeeper-3.4.6 目录,创建 data 目录:mkdir data
  5. 进入 conf 目录,把 zoo_sample.cfg 改名为 zoo.cfg:mv zoo_sample.cfg zoo.cfg
  6. 打开 zoo.cfg 文件,修改 dataDir 属性:dataDir=/usr/local/zookeeper-3.4.6/data

进入 Zookeeper 的 bin 目录,可管理 Zookeeper 服务:

  • 启动服务:./zkServer.sh start
  • 停止服务:./zkServer.sh stop
  • 查看服务状态:./zkServer.sh status

运行./zkServer.sh start将其启动。

项目结构

下面是示例工程的项目结构。包含父工程dubbo,接口模块dubbo-api、服务消费者模块dubbo-consumer和服务提供者模块dubbo-provider

dubbo              # 父工程
 ├─ dubbo-api      # 接口模块
 │ ├─ src
 │ │ └─ main
 │ │   └─ java
 │ │     └─ com
 │ │       └─ ming
 │ │         └─ api
 │ │           └─ service
 │ │             └─ HelloService.java
 │ └─ pom.xml
 ├─ dubbo-consumer # 服务消费者模块
 │ ├─ src
 │ │ └─ main
 │ │   ├─ java
 │ │   │ └─ org
 │ │   │   └─ ming
 │ │   │     └─ consumer
 │ │   │       ├─ controller
 │ │   │       │ └─ HelloController.java
 │ │   │       └─ DubboConsumerApplication.java
 │ │   └─ resources
 │ │     └─ application.yml
 │ └─ pom.xml
 ├─ dubbo-provider # 服务提供者模块
 │ ├─ src
 │ │ └─ main
 │ │   ├─ java
 │ │   │ └─ org
 │ │   │   └─ ming
 │ │   │     └─ provider
 │ │   │       ├─ service
 │ │   │       │ └─ HelloServiceImpl.java
 │ │   │       └─ DubboProviderApplication.java
 │ │   └─ resources
 │ │     └─ application.yml
 │ └─ pom.xml
 └─ pom.xml

父工程

父工程仅包含一个 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>org.ming</groupId>
    <artifactId>dubbo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
        <module>dubbo-api</module>
    </modules>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <dubbo.version>2.0.0</dubbo.version>
        <dubbo.api.version>1.0-SNAPSHOT</dubbo.api.version>
        <zkclient.version>0.11</zkclient.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
        </dependency>
    </dependencies>

</project>

接口模块

接口模块包含一个接口和一个 pom.xml 文件。

接口模块的作用是给出 API,在服务提供者与服务消费者之间建立契约。后面会看到,服务提供者会实现接口模块中的接口,服务消费者会调用对应接口中的方法。

package com.ming.api.service;

/**
 * Hello 服务接口
 */
public interface HelloService {
    /**
     * 问好
     *
     * @param name 姓名
     * @return 问好
     */
    String sayHello(String name);
}
<?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>
    <parent>
        <groupId>org.ming</groupId>
        <artifactId>dubbo</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>dubbo-api</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project>

服务提供者模块

服务提供者模块包含服务实现类、application.yml 和 pom.xml 文件。

服务实现类中使用了@Service注解,该注解用于标注一个类为一个 Dubbo 服务。

application.yml 中配置了 Zookeeper 地址,pom.xml 中引入了 dubbo、Zookeeper 相关依赖和dubbo-api

package org.ming.provider.service;

import com.alibaba.dubbo.config.annotation.Service;
import com.ming.api.service.HelloService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * Hello 服务实现
 */
@Service
@Component
@Slf4j
public class HelloServiceImpl implements HelloService {
    /**
     * 问好
     *
     * @param name 姓名
     * @return 问好
     */
    @Override
    public String sayHello(String name) {
        log.info("someone is calling me......");
        return "say hello to: " + name;
    }
}
server:
  port: 9090

spring:
  dubbo:
    application:
      name: spring-boot-demo-dubbo-provider
      registry: zookeeper://localhost:2181
<?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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.ming</groupId>
        <artifactId>dubbo</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <artifactId>dubbo-provider</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>dubbo-provider</name>
    <description>dubbo-provider</description>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.6.13</spring-boot.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </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>
        </dependency>
        <dependency>
            <groupId>com.alibaba.spring.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>${dubbo.version}</version>
        </dependency>
        <dependency>
            <groupId>com.101tec</groupId>
            <artifactId>zkclient</artifactId>
            <version>${zkclient.version}</version>
        </dependency>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>dubbo-api</artifactId>
            <version>${dubbo.api.version}</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
    <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>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>org.ming.provider.DubboProviderApplication</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

服务消费者模块

服务消费者模块包含控制器类、application.yml 和 pom.xml 文件。

控制器类中使用了@Reference注解,该注解用于将服务提供者的接口实现注入到控制器类中。

application.yml 中配置了 Zookeeper 地址,pom.xml 中引入了 dubbo、Zookeeper 相关依赖和dubbo-api

package org.ming.consumer.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.ming.api.service.HelloService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * Hello 服务 API
 */
@RestController
@Slf4j
public class HelloController {
    @Reference
    private HelloService helloService;

    @GetMapping("/sayHello")
    public String sayHello(@RequestParam(defaultValue = "ming") String name) {
        log.info("i'm ready to call someone......");
        return helloService.sayHello(name);
    }
}
server:
  port: 8080

spring:
  dubbo:
    application:
      name: spring-boot-demo-dubbo-consumer
      registry: zookeeper://localhost:2181
<?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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.ming</groupId>
        <artifactId>dubbo</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <artifactId>dubbo-consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>dubbo-consumer</name>
    <description>dubbo-consumer</description>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.6.13</spring-boot.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </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>
        </dependency>
        <dependency>
            <groupId>com.alibaba.spring.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>${dubbo.version}</version>
        </dependency>
        <dependency>
            <groupId>com.101tec</groupId>
            <artifactId>zkclient</artifactId>
            <version>${zkclient.version}</version>
        </dependency>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>dubbo-api</artifactId>
            <version>${dubbo.api.version}</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
    <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>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>org.ming.consumer.DubboConsumerApplication</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

启动服务并测试

启动服务提供者、服务消费者模块,访问 http://localhost:8080/sayHello?name=ming,收到如下响应说明成功:

say hello to: ming

参考:

spring-boot-demo/demo-dubbo at master · xkcoding/spring-boot-demo(代码基本复制自这里)

超详细,新手都能看懂!使用 SpringBoot+Dubbo 搭建一个简单的分布式服务

黑马程序员 Dubbo 快速入门,Java 分布式框架 dubbo 教程

另外使用了“通义灵码”来获取编写建议。