Dubbo3.0跨语言调用
# 1. 前言
在⼯作中,我们⽤ Java 语⾔通过 Dubbo 提供了⼀个服务,另外⼀个应⽤(也就是消费者)想要使⽤这个服务,如果消费者应⽤也是⽤ Java 语⾔开发的,那没什么好说的,直接在消费者应⽤引⼊ Dubbo 和服务接⼝相关的依赖即可。
但是,如果消费者应⽤不是⽤ Java 语⾔写的呢,⽐如是通过 python 或者 go 语⾔实现的,那就⾄少需要满⾜两个条件才能调⽤ Java 实现的 Dubbo 服务:
Dubbo ⼀开始是⽤ Java 语⾔实现的,那现在就需要⼀个 go 语⾔实现的 Dubbo 框架,也就是现在的
dubbo-go
,然后在go项⽬中引⼊ dubbo-go,从⽽可以在 go 项⽬中使⽤ dubbo,⽐如使⽤ go 语⾔去暴露和使⽤ Dubbo 服务。我们在使⽤ Java 语⾔开发⼀个 Dubbo 服务时,会把服务接⼝和相关类,单独抽象成为⼀个 Maven 项⽬,实际上就相当于⼀个单独的 jar 包,这个 jar 能被 Java 项⽬所使⽤,但不能被 go 项⽬所使⽤,所以 go 项⽬中该如何使⽤ Java 语⾔所定义的接⼝呢?直接⽤是不太可能的,只能通过间接的⽅式来解决这个问题,除开 Java 语⾔之外,那有没有其他技术也能定义接⼝呢?并且该技术也是 Java 和 go 都⽀持,这就是
protobuf
。
# 2. protobuf
我们可以通过 protobuf 来定义接⼝,然后通过 protobuf 的编译器将接⼝编译为特定语⾔的实现。
在 provider 项⽬中定义⼀个 userservice.proto
⽂件,路径为 src/main/proto/userservice.proto
:
syntax = "proto3";
package api;
option go_package = "./;api";
option java_multiple_files = true;
option java_package = "com.zhouyu";
option java_outer_classname = "UserServiceProto";
service UserService {
rpc GetUser (UserRequest) returns (User) {}
}
// The response message containing the greetings
message UserRequest {
string uid = 1;
}
// The response message containing the greetings
message User {
string uid = 1;
string username = 2;
}
相当于定义了⼀个 HelloService 服务,并且定义了⼀个 getUser ⽅法,接收 UserRequest 类型的参数,返回 User 类型的对象。
# 编译成Java
在provider项⽬中的pom⽂件中添加相关maven插件:
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.6.1</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.7.1:exe:${os.detected.classifier}</protocArtifact>
<outputDirectory>build/generated/source/proto/main/java</outputDirectory>
<clearOutputDirectory>false</clearOutputDirectory>
<protocPlugins>
<protocPlugin>
<id>dubbo</id>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-compiler</artifactId>
<version>0.0.3</version>
<mainClass>org.apache.dubbo.gen.dubbo.Dubbo3Generator</mainClass>
</protocPlugin>
</protocPlugins>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>build/generated/source/proto/main/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
并且可以把 common 依赖去掉,然后运⾏ provider 中 lifecycle 的 compile,就会进⾏编译了
并且会编译出对应的接⼝等信息,编译完成后,会⽣成⼀些类:
如果Java没有蓝⾊的,就
其中就包括了⼀个 UserService 接⼝,所以我们的 UserServiceImpl 就可以实现这个接⼝了:
@DubboService
public class UserServiceImpl implements UserService {
public User getUser(UserRequest userRequest) {
User user = User.newBuilder().setUid(userRequest.getUid()).setUsername("zhouyu").build();
return user;
}
}
⽽对于想要调⽤ UserService 服务的消费者⽽⾔,其实也是⼀样的改造,只需要使⽤同⼀份 userservice.proto
进⾏编译就可以了,⽐如现在有⼀个 go 语⾔的消费者。
# 3. go消费者调⽤java服务
⾸先,在IDEA中新建⼀个go模块:
然后把 userservice.proto 复制到 go-consumer/proto 下,然后进⾏编译,编译成为go语⾔对应的服务代码,只不过go语⾔中没有 maven 这种东⻄可以帮助我们编译,我们只能⽤原⽣的 protobuf 的编译器进⾏编译。
这就需要⼤家在机器上下载、安装protobuf的编译器:protoc
- 下载地址:https://github.com/protocolbuffers/protobuf/releases/download/v3.20.1/protoc-3.20.1-win64.zip (opens new window)
- 解压之后,把 protoc-3.20.1-win64\bin 添加到环境变量中去
- 在 cmd 中执⾏ protoc --version,能正常看到版本号即表示安装成功
另外还需要安装go:
下载地址:https://studygolang.com/dl/golang/go1.18.1.windows-amd64.msi (opens new window)
然后直接下⼀步安装
在cmd中(新开⼀个cmd窗⼝)执⾏go version,能正常看到版本号即表示安装成功
然后在 go-consumer 下新建⽂件夹 api,进⼊到 go-consumer/proto 下,运⾏:
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
go get -u github.com/dubbogo/tools/cmd/protoc-gen-go-triple
go install github.com/golang/protobuf/protoc-gen-go
go install github.com/dubbogo/tools/cmd/protoc-gen-go-triple
protoc -I. userservice.proto --go_out=../api --go-triple_out=../api
这样就会在 go-consumer/api
下⽣成⼀个 userservice.pb.go
⽂件和 userservice_triple.pb.go
⽂件
如果IDEA中提示要安装插件,就安装⼀下:
安装完之后,代码可能会报错,可以在 go-consumer ⽬录下执⾏命令下载依赖:
go mod tidy
然后就可以写go语⾔的服务消费者了,新建⼀个 consumer.go,内容为:
package main
import (
"context"
"dubbo.apache.org/dubbo-go/v3/common/logger"
"dubbo.apache.org/dubbo-go/v3/config"
_ "dubbo.apache.org/dubbo-go/v3/imports"
"go-consumer/api"
)
var userServiceImpl = new(api.UserServiceClientImpl)
// export DUBBO_GO_CONFIG_PATH=conf/dubbogo.yml
func main() {
config.SetConsumerService(userServiceImpl)
config.Load()
logger.Info("start to test dubbo")
req := &api.UserRequest{
Uid: "1",
}
user, err := userServiceImpl.GetUser(context.Background(), req)
if err != nil {
logger.Error(err)
}
logger.Infof("client response result: %v\n", user)
}
然后在 go-consumer 下新建 conf/dubbogo.yml
,⽤来配置注册中⼼:
dubbo:
registries:
demoZK:
protocol: zookeeper
address: 127.0.0.1:2181
consumer:
references:
UserServiceClientImpl:
protocol: tri
interface: com.zhouyu.UserService
注意这⾥配置的协议为 tri,⽽不是dubbo,在provider端也得把协议改为 tri:
然后就可以运⾏ consumer.go 了,只不过需要在 environment 中添加⼀个参数:
运⾏成功: