2021-10-17 dubbogo 基础使用

一、dubbogo相关介绍链接

1、Dubbo基本使用与原理详解

2、dubbogo 3.0:牵手 gRPC 走向云原生时代

3、快速上手 dubbo-go

4、dubbogo github page

5、dubbo-go examples

6、dubbbo 3.0 快速开始

7、hesson协议序列化example

二、安装zookeeper

这里我们使用zookeeper作为注册中心

1、安装docker-compose

 apt install docker-compose
image.png

2、编写docker-compose.yaml

mkdir zookeeper
cd zookeeper
vim docker-compose.yaml

输入如下内容并保存

version: '3'
services:
  zookeeper:
    image: zookeeper
    ports:
      - 2181:2181
  admin:
    image: apache/dubbo-admin:latest
    depends_on:
      - zookeeper
    ports:
      - 8081:8080
    environment:
      - admin.registry.address=zookeeper://zookeeper:2181
      - admin.config-center=zookeeper://zookeeper:2181
      - admin.metadata-report.address=zookeeper://zookeeper:2181

运行

docker-compose -f /home/jun/docker/zookeeper/docker-compose.yaml up -d

查看容器是否启动

image.png

主机浏览器打开地址查看dubbo-admin:http://192.168.96.129:8081
image.png

登录用户名密码均为root
192.168.96.129换为自己虚拟机的ip

三、JAVA

此文介绍一个示例,使用spring boot dubbojava客户端调用dubbo-gogo语言服务

3.1、初始化springboot dubbo

3.1.1、spring.io

1.png

按照图示新建一个项目,文件夹如下图:


image.png

3.1.2、转换为多module项目

将当前目录所有文件移动到名为dubbo-consumer的子目录下,然后在当前目录新增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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <packaging>pom</packaging>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <modules>
        <module>dubbo-client</module>
        <module>dubbo-consumer</module>
    </modules>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
</project>

修改dubbo-consumerpom文件内容为:

<?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>com.example</groupId>
        <artifactId>demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>dubbo-consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>dubbo-demo-consumer</name>
    
    <properties>
        <skip_maven_deploy>false</skip_maven_deploy>
        <dubbo.version>2.7.14</dubbo.version>
        <curator.version>2.12.0</curator.version>
        <zk.version>3.4.14</zk.version>
    </properties>
    <dependencies>
        <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>
        <!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-spring-boot-starter -->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>${dubbo.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-dependencies-zookeeper -->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-dependencies-zookeeper</artifactId>
            <version>${dubbo.version}</version>
            <type>pom</type>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>dubbo-client</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

新建子项目dubbo-client,用于存放dubbogo适配的接口类,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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.example</groupId>
        <artifactId>demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    
    <artifactId>dubbo-client</artifactId>
</project>

3.1.3、最后项目的目录情况:

image.png
  • --> 1: dubbogo互通协议的interface接口
  • --> 2: dubbogo互通协议的dto请求响应类型
  • --> 3: dubbogo消费端的请求接口类
  • --> 4: dubbogo消费端的配置文件

3.2、代码编写

3.2.1、dubbo-client

  • QueryUserParam
package com.demo.exp.dto;

import lombok.Data;

import java.io.Serializable;

@Data
public class QueryUserParam implements Serializable {
    private String userName;
    private String userId;
}
  • QueryUserResponse
package com.demo.exp.dto;

import lombok.Data;

import java.io.Serializable;

@Data
public class QueryUserResponse implements Serializable {
    private String userId;
    private String userName;
    private String birthDate;
    private long age;
    private boolean isDead;
}
  • UserService
package com.demo.exp.service;

import com.demo.exp.dto.QueryUserParam;
import com.demo.exp.dto.QueryUserResponse;

public interface UserService {
    QueryUserResponse QueryUser(QueryUserParam req);
}

3.2.2、dubbo-consumer

  • dto.Result
package com.example.demo.dto;

import lombok.Getter;
import lombok.Setter;

import java.io.Serializable;

@Getter
@Setter
public class Result<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    // 业务码code
    private int resultCode;
    // 返回信息
    private String message;
    // 返回的数据
    private T data;

    public Result(){}

    public Result(int code, String message){
        this.resultCode = code;
        this.message = message;
    }

    @Override
    public String toString(){
        return "Result{" +
                "resultCode=" + resultCode +
                ", message='" + message + "'" +
                ", data=" + data +
                "}";
    }

}
  • dto.ResultGenerator
package com.example.demo.dto;

import org.springframework.util.StringUtils;

public class ResultGenerator {
    private static final String DEFAULT_SUCCESS_MESSAGE = "success";
    private static final String DEFAULT_FAIL_MESSAGE = "fail";
    private static final int RESULT_CODE_SUCCESS = 200;
    private static final  int RESULT_CODE_SERVER_ERROR = 500;

    public static Result genSuccessResult(){
        Result res = new Result();
        res.setResultCode(RESULT_CODE_SUCCESS);
        res.setMessage(DEFAULT_SUCCESS_MESSAGE);
        return res;
    }

    public static Result genSuccessResult(String msg){
        Result res = new Result();
        res.setResultCode(RESULT_CODE_SUCCESS);
        res.setMessage(msg);
        return res;
    }

    public static Result genSuccessResult(Object data){
        Result res = new Result();
        res.setResultCode(RESULT_CODE_SUCCESS);
        res.setMessage(DEFAULT_SUCCESS_MESSAGE);
        res.setData(data);
        return res;
    }

    public static Result genFailResult(String msg){
        Result res = new Result();
        res.setResultCode(RESULT_CODE_SERVER_ERROR);
        if(!StringUtils.hasLength(msg)){
            res.setMessage(DEFAULT_FAIL_MESSAGE);
        }else{
            res.setMessage(msg);
        }
        return res;
    }

    public static Result genErrorResult(int code, String msg){
        Result res = new Result();
        res.setResultCode(code);
        res.setMessage(msg);
        return res;
    }
}
  • UserController
package com.example.demo.controllers;

import com.demo.exp.dto.QueryUserParam;
import com.demo.exp.dto.QueryUserResponse;
import com.demo.exp.service.UserService;
import com.example.demo.dto.Result;
import com.example.demo.dto.ResultGenerator;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.rpc.RpcContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/user")
@Slf4j
public class UserController {
    @DubboReference(retries = 0, timeout = 1000 * 60, application = "dubbogo-demo", group = "dubbo-service", version = "1.0.0")
    UserService userService;

    @GetMapping("/query")
    @ResponseBody
    public Result QueryUser(){
        QueryUserParam req = new QueryUserParam();
        req.setUserName("test");
        RpcContext rpcContext = RpcContext.getContext();
        rpcContext.setAttachment("app", "dubbo-consumer");
        QueryUserResponse resp = null;
        try{
            resp = userService.QueryUser(req);
        }catch (Throwable e){
            log.error("QueryUser error", e);
            return ResultGenerator.genFailResult(e.getMessage());
        }
        return ResultGenerator.genSuccessResult(resp);
    }
}
  • application.yml配置文件
server:
  port: 7000

spring:
  application:
    name: dubbo-consumer
logging:
  level:
    root: info

#dubbo
dubbo:
  application:
    name: dubbo-consumer
  registry:
    address: zookeeper://192.168.96.129:2181
    timeout: 60000
  protocal:
    name: dubbo
  consumer:
    retries: 1
    check: false

四、go

4.1、初始化go项目

mkdir dubbogodemo
cd dubbogodemo
go mod init dubbo-demo
go get github.com/pkg/errors
go get dubbo.apache.org/dubbo-go/v3@3.0
image.png

4.2、 编写go代码

4.2.1、项目结构

image.png
  • --> 1: dubbogo互通协议的dto请求响应类型
  • --> 2: dubbogo互通协议的interface实现
  • --> 3: 工具类
  • --> 4: dubbogo服务提供方的配置文件
  • --> 5: dubbogo服务启动工具

4.2.2、dto

  • UserRequest
package dto

type UserRequest struct {
    UserName string // 用户名
    UserId string // 用户id
}

func(req UserRequest) JavaClassName() string{
    return "com.demo.exp.dto.QueryUserParam"
}
  • UserResponse
package dto

type UserResponse struct {
    UserName string // 用户名
    UserId string // 用户id
    BirthDate string // 出生日期
    Age int64 // 年龄
    IsDead bool // 是否已去世
}

func(req UserResponse) JavaClassName() string{
    return "com.demo.exp.dto.QueryUserResponse"
}

4.2.3、service

  • UserService
package service

import (
    "context"
    "dubbo-demo/pkg/dto"
    "dubbo-demo/pkg/util"
    "github.com/pkg/errors"
    "time"
)

type UserService struct {

}

func (u *UserService) Reference() string {
    return "UserService"
}

func (u *UserService) QueryUser(ctx context.Context, in *dto.UserRequest)(*dto.UserResponse, error){
    appName := util.GetDubboContextAppName(ctx)
    if appName == ""{
        return nil, errors.Errorf("auth error, no appname")
    }
    if appName != "dubbo-consumer"{
        return nil, errors.Errorf("auth error, not allowed")
    }
    if in.UserId != ""{
        if in.UserId != "123456789"{
            return nil, errors.Errorf("no user found with id[%s]", in.UserId)
        }
        return &dto.UserResponse{
            UserName:  "dubbo-user1",
            UserId:    "123456789",
            BirthDate: util.GetCommonTimeStr(time.Now().Add(-56 * 360 * 24 * time.Hour)),
            Age:       56,
            IsDead:    true,
        }, nil
    }
    if in.UserName == ""{
        return nil, errors.Errorf("please input query condition")
    }
    return &dto.UserResponse{
        UserName:  in.UserName,
        UserId:    "666666666",
        BirthDate: util.GetCommonTimeStr(time.Now().Add(-30 * 360 * 24 * time.Hour)),
        Age:       30,
        IsDead:    false,
    }, nil
}

4.2.2、util


func GetDubboContextAppName(ctx context.Context)(appName string){
    ctxMap, ok := ctx.Value(constant.DubboCtxKey("attachment")).(map[string]interface{})
    if !ok{
        return
    }
    if str, ok := ctxMap["app"]; ok{
        appName, _ = str.(string)
    }
    return
}

func GetCommonTimeStr(t time.Time) string{
    return t.Format("2006-01-02 15:04:05")
}

4.2.4、dubbo.yml

# dubbo server yaml configure file

dubbo:
  application:
    name: dubbogo-demo
    module: dubbogo
    version: 1.0.0
    owner: demo
  registries:
    demoZK:
      protocol: zookeeper
      timeout: 3s
      address: 192.168.96.129:2181
  protocols:
    dubbo:
      name: dubbo
      port: 20000
  provider:
    register: true
    registryIDs:
      - demoZK
    services:
      UserService:
        protocol: dubbo
        interface: com.demo.exp.service.UserService
        group: dubbo-service
        version: 1.0.0
        loadbalance: random
        warmup: 100
        cluster: failover
        methods:
          - name: QueryUser
            retries: 1
            loadbalance: random
  logger:
    zap-config:
      level: info

4.2.5、cmd

  • cmd.go
package cmd

import (
    "dubbo-demo/pkg/dto"
    "dubbo-demo/pkg/service"
    "dubbo.apache.org/dubbo-go/v3/config"
    _ "dubbo.apache.org/dubbo-go/v3/imports"

    hessian "github.com/apache/dubbo-go-hessian2"
)

func StartDubboServer(){
    config.SetProviderService(&service.UserService{})
    hessian.RegisterPOJO(&dto.UserRequest{})
    hessian.RegisterPOJO(&dto.UserResponse{})

    err := config.Load(config.WithPath("./conf/dubbo.yml"))
    if err != nil{
        panic(err)
    }
    select {
    }
}
  • main.go
package main

import (
    "dubbo-demo/cmd"
)

func main(){
    cmd.StartDubboServer()
}

4.3、go mod

如果import包有问题或者报错,按照如下操作试试

go mod tidy
go get dubbo.apache.org/dubbo-go/v3@3.0
go mod tidy

五、运行测试

5.1、启动go项目

goland按照如下配置运行:

image.png

启动后,在dubbo admin可以看到服务已经注册:
image.png

详情页服务提供者可以看到运行种服务的ip和端口:


image.png

此时,消费者没有信息。

5.2、启动java项目

idea按照如下配置运行:

image.png

启动后,在dubbo admin服务详情页可以看到消费者信息:
image.png

5.3、调用测试

调用java项目的api接口,api会通过dubbo协议调用到go项目的服务。
浏览器打开地址: 127.0.0.1:7000/api/user/query
得到如下返回:

{
    "resultCode": 200,
    "message": "success",
    "data":
    {
        "userId": "666666666",
        "userName": "test",
        "birthDate": "1992-03-23 20:50:05",
        "age": 30,
        "dead": false
    }
}

修改代码,当有错误error时,返回如下:

{
    "resultCode": 500,
    "message": "no user found with id[666]"
}

六、项目代码

dubbogo example in github

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容