dubbo的springboot集成

1.什么是dubbo?

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

以上是官方的解释,我个人的理解,dubbo作为一个RPC服务开发框架,除了满足我微服务之间远程调用的目的之外,还能有以下几个重要的点。

1.和nacos等注册中心,完成dubbo接口服务的服务发现,消费方调用接口无需关注服务端的ip、端口

2.和sentinel集成,可以完成限流和熔断的目的

3.dubbo实现了多个负载均衡算法,只需yml文件配置即可。

4.dubbo和seata可以很方便的集成,轻松达到业务数据一致性的目的。

2.dubbo的常用注解

@EnableDubbo:创建Springboot启动类,需添加@EnableDubbo注解,开启Dubbo自动配置功能

@DubboService:Dubbo会将对应的服务注册到spring, 在spring启动后调用对应的服务导出方法,将服务注册到注册中心, 这样Consumer端才能发现我们发布的服务并调用(与spring的@Service注解作用类似)

@DubboReference:通过@DubboReference注解对需要调用的服务进行引入。即可像调用本地方法一样调用远程服务了。(和spring的@Autowired功能类似)

*注@DubboService 和**@DubboReference**的version参数和group参数的值必须一致。这两个参数可以确定一个实现类,接口一般可以有多个实现类的,多个实现类可以通过version和group参数进行区分。

3.代码示例

示例需要三个工程,一个接口定义、一个服务端,一个消费端。

maven依赖的版本号取决于项目使用的springboot版本及springcloud版本,我使用的版本如下:

XML 复制代码
<!-- SpringBoot的依赖配置-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.6.11</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2021.0.1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2021.0.4.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-bom</artifactId>
                <version>3.0.9</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

3.1接口示例代码

工程名称:dubbo-demo-interface

实体类必须实现序列化接口,因为在远程调用时,实体类数据是序列化后传输的

java 复制代码
package com.jc.shop.dubbo.demo.domain;

/**
 * 用户表
 */
public class User implements java.io.Serializable{

    /**
     * 主键ID
     */
    private long id;

    /**
     * 用户名称
     */
    private String name;

    /**
     * 所属部门
     */
    private long deptId;

    /**
     * 岗位
     */
    private String post;

    private Dept dept;

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    public long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public long getDeptId() {
        return deptId;
    }

    public void setDeptId(long deptId) {
        this.deptId = deptId;
    }

    public String getPost() {
        return post;
    }

    public void setPost(String post) {
        this.post = post;
    }
}

接口定义:

java 复制代码
package com.jc.shop.dubbo.demo.service;

import com.jc.shop.dubbo.demo.domain.User;

/**
 * 业务接口
 */
public interface IUserService {


    public int insert(User user);
}

3.2服务端示例

服务端工程名:dubbo-demo-provider

jar包依赖,maven

XML 复制代码
        <!-- dubbo与spring集成,可实现dubbo的自动初始化 -->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
        </dependency>

        <!-- 实现将dubbo的服务注册到nacos -->
        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
        </dependency>

        <!-- nacos的相关依赖 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

        <!-- 加载bootstrap.yml文件 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>

        <!-- 引入接口层jar包 -->
        <dependency>
            <groupId>com.jc</groupId>
            <artifactId>dubbo-demo-interface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

yml配置

bash 复制代码
dubbo:
  application:
    name: dubbo-provider
  protocol:  #dubbo协议信息
    name: dubbo
    host: 127.0.0.1
    port: 20881

  registry:
    address: nacos://localhost:8848  #使用nacos作为注册中心

服务层的代码实现:

java 复制代码
package com.jc.shop.dubbo.demo.service.impl;

import com.jc.shop.dubbo.demo.domain.User;
import com.jc.shop.dubbo.demo.mapper.UserMapper;
import com.jc.shop.dubbo.demo.service.IUserService;
import io.seata.core.context.RootContext;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 业务层接口,@Service注解不用加,因为我在当前工程的controller中需要调用,所以加了@Service注解
 */
@Service
@DubboService(version = "1.0.0",loadbalance = "leastactive")//负载策略为"最少活跃优先 + 加权随机"
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserMapper mapper;

    @Override
    public int insert(User user) {
        //以下打印信息是为了集成seata框架的,可忽略,本次不涉及seata框架内容
        System.out.println("用户新增的事务ID为:"+ RootContext.getXID());
        return mapper.insert(user);
    }
}

在当前工程的启动类中,添加@EnableDubbo注解,开启dubbo配置的自动配置功能:

java 复制代码
package com.jc;

import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableDubbo
public class DubboProviderApplication {
    public static void main(String[] args) {
        //以下4个变量的设置是为了避免同一台机器,启动多个dubbo服务,缓存默认使用的同一个地址会报错。
        System.setProperty("dubbo.meta.cache.filePath","/media/zhangzz/localDisk/home/zhangzz/dubbo/provider/");
        System.setProperty("dubbo.meta.cache.fileName","provider");

        System.setProperty("dubbo.mapping.cache.filePath","/media/zhangzz/localDisk/home/zhangzz/dubbo/provider/");
        System.setProperty("dubbo.mapping.cache.fileName","provider1");
        SpringApplication.run(DubboProviderApplication.class,args);
    }
}

3.3消费端代码示例

消费端工程名:dubbo-demo-consumer

maven依赖配置:

XML 复制代码
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>3.2.7</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
        </dependency>

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

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

yml配置:

bash 复制代码
dubbo:
  application:
    name: dubbo-consumer
  protocol:  #dubbo协议信息
    name: dubbo
    port: -1   # -1表示端口随机
  registry:
    address: nacos://localhost:8848  #nacos地址

业务层代码调用:

java 复制代码
package com.jc.shop.dubbo.demo.service.impl;

import com.jc.shop.dubbo.demo.domain.User;
import com.jc.shop.dubbo.demo.service.IConsumerService;
import com.jc.shop.dubbo.demo.service.IUserService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

@Service
public class ConsumerServiceImpl implements IConsumerService {


    @DubboReference(version = "1.0.0")  //版本号需和服务端一致,若有group,也需保持一致
    private IUserService userService;

    @Override
    public int insertUser(User user) {

        int j = userService.insert(user);
        System.out.println("用户新增,影响行数:"+j);


        return j;
    }
}

controller层代码:

java 复制代码
package com.jc.shop.dubbo.demo.controller;

import com.jc.core.domain.AjaxResult;
import com.jc.shop.dubbo.demo.domain.User;
import com.jc.shop.dubbo.demo.service.IConsumerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/demo")
public class DemoController {


    @Autowired
    private IConsumerService service;

    @PostMapping("/insert")
    public AjaxResult insert(@RequestBody User user){

        int i = service.insertUser(user);
        if(i>0) {
            return AjaxResult.success("success");
        }else{
            return AjaxResult.error();
        }
    }
}

应用启动类:

java 复制代码
package com.jc;

import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableDubbo
public class DubboConsumerApplication {
    public static void main(String[] args) {
        System.setProperty("dubbo.meta.cache.filePath","/media/zhangzz/localDisk/home/zhangzz/dubbo/consumer/");
        System.setProperty("dubbo.meta.cache.fileName","consumer");

        System.setProperty("dubbo.mapping.cache.filePath","/media/zhangzz/localDisk/home/zhangzz/dubbo/consumer/");
        System.setProperty("dubbo.mapping.cache.fileName","consumer1");
        SpringApplication.run(DubboConsumerApplication.class,args);
    }
}

启动之后,访问http://localhost:8082/demo/insert地址

4.与sentinel集成

集成的配置可参考《sentinel-单机流量控制》或《sentinel-集群流量控制》,此处不再赘述。此处只说明下限流、熔断的资源名称如何定义:

以我的代码为例,规则定义如下:

java 复制代码
FlowRule flowRule = new FlowRule(IUserService.class.getName())
        .setCount(10)
        .setGrade(RuleConstant.FLOW_GRADE_QPS);
FlowRuleManager.loadRules(Collections.singletonList(flowRule));

由以上代码可以看出,资源名称是类的全路径"com.jc.shop.dubbo.demo.service.IUserService",一般我们的流控规则都是在nacos中配置,由代码动态加载。nacos中的配置如下:

javascript 复制代码
[
    {
        "resource":"com.jc.shop.dubbo.demo.service.IUserService", 
        "limitApp":"default",  
        "grade":1,            
        "count":1,            
        "strategy":0,         
        "controlBehavior":0,  
        "clusterMode":false
    }
]

官方文档传送门:dubbo与Sentinel集成的限流示例

5.负载均衡

目前 Dubbo 内置了如下负载均衡算法,用户可直接配置使用:

算法 特性 备注 配置值
Weighted Random LoadBalance 加权随机 默认算法,默认权重相同 random (默认)
RoundRobin LoadBalance 加权轮询 借鉴于 Nginx 的平滑加权轮询算法,默认权重相同, roundrobin
LeastActive LoadBalance 最少活跃优先 + 加权随机 背后是能者多劳的思想 leastactive
Shortest-Response LoadBalance 最短响应优先 + 加权随机 更加关注响应速度 shortestresponse
ConsistentHash LoadBalance 一致性哈希 确定的入参,确定的提供者,适用于有状态请求 consistenthash
P2C LoadBalance Power of Two Choice 随机选择两个节点后,继续选择"连接数"较小的那个节点。 p2c
Adaptive LoadBalance 自适应负载均衡 在 P2C 算法基础上,选择二者中 load 最小的那个节点 adaptive

5.1 使用方式

@DubboService(loadbalance = "leastactive")

@DubboReference(loadbalance = "leastactive")

服务端方法级别的负载配置:

@DubboService(method={@Method(name="insert",loadbalance = "leastactive")})

消费端方法级别的负载配置:

@DubboReference(method={@Method(name="insert",loadbalance = "leastactive")})

相关推荐
向前看-2 小时前
验证码机制
前端·后端
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭3 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
超爱吃士力架4 小时前
邀请逻辑
java·linux·后端
AskHarries6 小时前
Spring Cloud OpenFeign快速入门demo
spring boot·后端
isolusion7 小时前
Springboot的创建方式
java·spring boot·后端
Yvemil77 小时前
《开启微服务之旅:Spring Boot Web开发举例》(一)
前端·spring boot·微服务
zjw_rp7 小时前
Spring-AOP
java·后端·spring·spring-aop
TodoCoder7 小时前
【编程思想】CopyOnWrite是如何解决高并发场景中的读写瓶颈?
java·后端·面试
凌虚8 小时前
Kubernetes APF(API 优先级和公平调度)简介
后端·程序员·kubernetes
星河梦瑾8 小时前
SpringBoot相关漏洞学习资料
java·经验分享·spring boot·安全