JDK 8,Golang >= 1.15,Dubbo 3.0.2,zookeeper 啟動(dòng),
// The response message containing the greetings
message User {
string name = 1;
string id = 2;
int32 age = 3;
}
proto for Java
// The response message containing the greetings
message User {
string name = 1;
string id = 2;
int32 age = 3;
}
Hessian 序列化
type User struct {
ID string
Name string
Age int32
}
func (u *User) JavaClassName() string {
return "org.apache.dubbo.User"
}
func init(){
hessian.RegisterPOJO(&User{})
}
POJO for Java
package org.apache.dubbo
public class User {
private String id;
private String name;
private int age;
}
public interface IGreeter {
/**
* <pre>
* Sends a greeting
* </pre>
*/
User sayHello(HelloRequest request);
}
Go client (由protoc-gen-go-triple 根據(jù) proto 文件自動(dòng)生成)
type GreeterClientImpl struct {
// Sends a greeting
SayHello func(ctx context.Context, in *HelloRequest) (*User, error)
}
Go server (由開(kāi)發(fā)者定義)
type GreeterProvider struct {
api.GreeterProviderBase
}
func (s *GreeterProvider) SayHello(ctx context.Context, in *api.HelloRequest) (*api.User, error) {
logger.Infof("Dubbo3 GreeterProvider get user name = %s\n", in.Name)
return &api.User{Name: "Hello " + in.Name, Id: "12345", Age: 21}, nil
}
Go 方法需要遵守 Dubbo-go 3.0 用戶(hù)服務(wù)接口定義規(guī)范
references:
GreeterClientImpl:
protocol: tri
interface: com.apache.dubbo.sample.basic.IGreeter # must be compatible with grpc or dubbo-java
group: dubbogo # 需要與服務(wù)端對(duì)應(yīng) 默認(rèn)為空
version: v1.0.1 # 需要與服務(wù)端對(duì)應(yīng) 默認(rèn)為空
Go-server:
services:
GreeterProvider:
protocol-ids: tripleProtocol
interface: com.apache.dubbo.sample.basic.IGreeter # must be compatible with grpc or dubbo-java
group: dubbogo # 需要與服務(wù)端對(duì)應(yīng) 默認(rèn)為空
version: v1.0.1 # 需要與服務(wù)端對(duì)應(yīng) 默認(rèn)為空
參考 dubbo-go-samples/helloworld
syntax = "proto3";
option java_package = "org.apache.dubbo.sample.hello";
package helloworld;
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message User {
string name = 1;
string id = 2;
int32 age = 3;
}
該接口描述文件定義了將會(huì)生成的 Java 類(lèi) org.apache.dubbo.sample.hello.Helloworld,以及類(lèi)中包含的傳輸結(jié)構(gòu) HelloRequest 和 User 類(lèi)。
package com.apache.dubbo.sample.basic;
// 引入根據(jù) PB 生成的類(lèi)
import org.apache.dubbo.sample.hello.Helloworld.User;
import org.apache.dubbo.sample.hello.Helloworld.HelloRequest;
public interface IGreeter {
/**
* <pre>
* Sends a greeting
* </pre>
*/
// 定義接口
User sayHello(HelloRequest request);
}
package com.apache.dubbo.sample.basic;
import org.apache.dubbo.sample.hello.Helloworld.User;
import org.apache.dubbo.sample.hello.Helloworld.HelloRequest;
public class IGreeter1Impl implements IGreeter {
@Override
public User sayHello(HelloRequest request) {
System.out.println("receiv: " + request);
User usr = User.newBuilder()
.setName("hello " + request.getName())
.setAge(18)
.setId("12345").build();
return usr;
}
}
package com.apache.dubbo.sample.basic;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
import java.util.concurrent.CountDownLatch;
public class ApiProvider {
public static void main(String[] args) throws InterruptedException {
ServiceConfig<IGreeter> service = new ServiceConfig<>();
service.setInterface(IGreeter.class);
service.setRef(new IGreeter1Impl());
// 使用 Triple 協(xié)議
service.setProtocol(new ProtocolConfig(CommonConstants.TRIPLE, 50051));
service.setApplication(new ApplicationConfig("demo-provider"));
// 使用 ZK 作為注冊(cè)中心
service.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181"));
service.export();
System.out.println("dubbo service started");
new CountDownLatch(1).await();
}
}
啟動(dòng)服務(wù),可看到輸出如下日志,代表 Java Triple Server 啟動(dòng)成功
main INFO bootstrap.DubboBootstrap: [DUBBO] DubboBootstrap has started., dubbo version: 3.0.2, current host: 192.168.0.108
dubbo service started
對(duì)于已經(jīng)啟動(dòng)的Dubbo服務(wù),如需要開(kāi)發(fā)與其對(duì)應(yīng)的Go-client,需要進(jìn)行如下步驟:
1.編寫(xiě)與 Java 適配的 proto文件samples_api.proto
syntax = "proto3";
package api; // pacakge 名隨意指定
// necessary
option go_package = "./;api";
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (User) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message User {
string name = 1;
string id = 2;
int32 age = 3;
}
2.使用 protoc-gen-triple 生成接口文件
protoc -I . samples_api.proto --triple_out=plugins=triple:.
3.撰寫(xiě)配置文件: dubbogo.yml
dubbo:
registries:
demoZK:
protocol: zookeeper
address: 127.0.0.1:2181
consumer:
references:
GreeterClientImpl:
protocol: tri
interface: com.apache.dubbo.sample.basic.IGreeter # must be compatible with grpc or dubbo-java
4.撰寫(xiě) main.go 文件,發(fā)起調(diào)用
// 引入生成的接口結(jié)構(gòu)
var grpcGreeterImpl = new(api.GreeterClientImpl)
// export DUBBO_GO_CONFIG_PATH=dubbogo.yml
func main() {
config.SetConsumerService(grpcGreeterImpl)
if err := config.Load(); err != nil {
panic(err)
}
time.Sleep(3 * time.Second)
logger.Info("start to test dubbo")
req := &api.HelloRequest{
Name: "laurence",
}
reply, err := grpcGreeterImpl.SayHello(context.Background(), req)
if err != nil {
logger.Error(err)
}
logger.Infof("client response result: %v\n", reply)
}
5.可查看到調(diào)用成功的日志
cmd/client.go:53 client response result: name:"hello laurence" id:"12345" age:18
receiv: name: "laurence"
1.定義配置文件
dubbo:
registries:
demoZK:
protocol: zookeeper
address: 127.0.0.1:2181
protocols:
triple:
name: tri
port: 20000
provider:
services:
GreeterProvider:
interface: com.apache.dubbo.sample.basic.IGreeter # must be compatible with grpc or dubbo-java
2.引入傳輸結(jié)構(gòu),定義服務(wù)
type GreeterProvider struct {
api.GreeterProviderBase
}
func (s *GreeterProvider) SayHello(ctx context.Context, in *api.HelloRequest) (*api.User, error) {
logger.Infof("Dubbo3 GreeterProvider get user name = %s\n", in.Name)
return &api.User{Name: "Hello " + in.Name, Id: "12345", Age: 21}, nil
}
3.啟動(dòng)服務(wù)
// export DUBBO_GO_CONFIG_PATH=dubbogo.yml
func main() {
config.SetProviderService(&GreeterProvider{})
if err := config.Load(); err != nil {
panic(err)
}
select {}
}
public class ApiConsumer {
public static void main(String[] args) throws InterruptedException, IOException {
ReferenceConfig<IGreeter> ref = new ReferenceConfig<>();
ref.setInterface(IGreeter.class);
ref.setCheck(false);
ref.setProtocol(CommonConstants.TRIPLE);
ref.setLazy(true);
ref.setTimeout(100000);
ref.setApplication(new ApplicationConfig("demo-consumer"));
ref.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181"));
final IGreeter iGreeter = ref.get();
System.out.println("dubbo ref started");
Helloworld.HelloRequest req = Helloworld.HelloRequest.newBuilder().setName("laurence").build();
try {
final Helloworld.User reply = iGreeter.sayHello(req);
TimeUnit.SECONDS.sleep(1);
System.out.println("Reply:" + reply);
} catch (Throwable t) {
t.printStackTrace();
}
System.in.read();
}
}
1.定義 Java 接口、參數(shù)和返回值,可參考 Dubbo 快速開(kāi)始
package org.apache.dubbo;
// 需要暴露的服務(wù)接口
public interface UserProvider {
User getUser(int usercode);
}
package org.apache.dubbo;
public class User implements Serializable {
private String id;
private String name;
private int age;
private Date time = new Date();
/* ... */
}
2.實(shí)現(xiàn)服務(wù)接口:
UserProviderImpl.java
package org.apache.dubbo;
public class UserProviderImpl implements UserProvider {
public User getUser(int userCode) {
return new User(String.valueOf(userCode), "userCode get", 48);
}
}
3.使用SpringBoot 啟動(dòng)
Provider.java
package org.apache.dubbo;
// use when config by API
/*
import java.util.concurrent.CountDownLatch;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
*/
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Provider {
// main function, config from spring boot
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo.provider.xml"});
context.start();
System.in.read(); // press any key to exit
}
// config by API
// public static void startComplexService() throws InterruptedException {
// ServiceConfig<ComplexProvider> service = new ServiceConfig<>();
// service.setInterface(ComplexProvider.class);
// service.setRef(new ComplexProviderImpl());
// service.setProtocol(new ProtocolConfig(CommonConstants.DUBBO_PROTOCOL, 20001));
// service.setApplication(new ApplicationConfig("demo-provider"));
// service.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181"));
// service.export();
// System.out.println("dubbo service started");
// new CountDownLatch(1).await();
// }
}
4.通過(guò)Spring 配置 Dubbo 參數(shù)Resources/META-INF.spring/dubbo.provider.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- 應(yīng)用名 -->
<dubbo:application name="user-info-server"/>
<!-- 連接到哪個(gè)本地注冊(cè)中心 -->
<dubbo:registry id="dubbogo" address="zookeeper://127.0.0.1:2181" />
<!-- 用dubbo協(xié)議在20880端口暴露服務(wù) -->
<dubbo:protocol id="dubbo" name="dubbo" host="127.0.0.1" port="20010" />
<!-- 聲明需要暴露的服務(wù)接口 -->
<dubbo:service id="aaa" registry="dubbogo" timeout="3000" interface="org.apache.dubbo.UserProvider" ref="demoService"/>
<dubbo:service id="bbb" registry="dubbogo" timeout="3000" interface="org.apache.dubbo.UserProvider" ref="otherService" version="2.0"/>
<dubbo:service id="ccc" registry="dubbogo" timeout="3000" interface="org.apache.dubbo.UserProvider" ref="otherService" group="as" version="2.0"/>
<bean id="demoService" class="org.apache.dubbo.UserProviderImpl" />
<bean id="otherService" class="org.apache.dubbo.UserProviderAnotherImpl"/>
</beans>
啟動(dòng)Provider類(lèi),可看到輸出如下日志,代表 Dubbo Server 啟動(dòng)成功
[DUBBO] DubboBootstrap is ready., dubbo version: 2.7.7, current host: 127.0.0.1
[DUBBO] DubboBootstrap has started., dubbo version: 2.7.7, current host: 127.0.0.1
對(duì)于已經(jīng)啟動(dòng)的Dubbo服務(wù),如需要開(kāi)發(fā)與其對(duì)應(yīng)的Go-client,需要進(jìn)行如下步驟:
1.編寫(xiě)與 Java 適配的 POJO 類(lèi) User
import(
hessian "github.com/apache/dubbo-go-hessian2"
)
// 字段需要與 Java 側(cè)對(duì)應(yīng),首字母大寫(xiě)
type User struct {
ID string
Name string
Age int32
Time time.Time
}
func (u *User) JavaClassName() string {
return "org.apache.dubbo.User" // 需要與 Java 側(cè) User 類(lèi)名對(duì)應(yīng)
}
func init(){
hessian.RegisterPOJO(&pkg.User{}) // 注冊(cè) POJO
}
2.編寫(xiě)與 Java 側(cè)一致的客戶(hù)端存根類(lèi),其接口方法需要與Java側(cè)對(duì)應(yīng)規(guī)定第一個(gè)參數(shù)必須為 context.Context,最后一個(gè)返回值必須為 error
import(
"dubbo.apache.org/dubbo-go/v3/config"
)
var (
userProvider = &pkg.UserProvider{}
)
// UserProvider 客戶(hù)端存根類(lèi)
type UserProvider struct {
// dubbo標(biāo)簽,用于適配go側(cè)客戶(hù)端大寫(xiě)方法名 -> java側(cè)小寫(xiě)方法名,只有 dubbo 協(xié)議客戶(hù)端才需要使用
GetUser func(ctx context.Context, req int32) (*User, error) `dubbo:"getUser"`
}
func init(){
// 注冊(cè)客戶(hù)端存根類(lèi)到框架,實(shí)例化客戶(hù)端接口指針 userProvider
config.SetConsumerService(userProvider)
}
3.撰寫(xiě)配置文件: dubbogo.yml
dubbo:
registries:
demoZK: # 定義注冊(cè)中心ID
protocol: zookeeper
timeout: 3s
address: 127.0.0.1:2181
consumer:
references:
UserProvider: # 存根類(lèi)名
protocol: dubbo # dubbo 協(xié)議,默認(rèn) hessian2 序列化方式
interface: org.apache.dubbo.UserProvider # 接口需要與Java側(cè)對(duì)應(yīng)
logger:
zap-config:
level: info # 日志級(jí)別
或者使用Triple + Hessian2 序列化請(qǐng)求Server。本例子如果跟Java Server互通則不能用Triple。
dubbo:
registries:
demoZK:
protocol: zookeeper
timeout: 3s
address: 127.0.0.1:2181
consumer:
references:
UserProvider:
protocol: tri # triple 協(xié)議
serialization: hessian2 # 序列化方式 hessian2,triple 協(xié)議默認(rèn)為 pb 序列化,不配置會(huì)報(bào)錯(cuò)
interface: org.apache.dubbo.UserProvider
logger:
zap-config:
level: info
4.撰寫(xiě) main.go 文件,發(fā)起調(diào)用
func main(){
config.Load()
var i int32 = 1
user, err := userProvider.GetUser2(context.TODO(), i)
if err != nil {
panic(err)
}
logger.Infof("response result: %v", user)
}
5.可查看到調(diào)用成功的日志,符合預(yù)期
response result: User{ID:1, Name:userCode get, Age:48, Time:2021-10-21 20:25:26.009 +0800 CST}
1.定義配置文件
dubbo:
registries:
demoZK:
protocol: zookeeper
address: 127.0.0.1:2181
protocols:
dubbo:
name: dubbo
port: 20000
provider:
services:
UserProvider:
interface: org.apache.dubbo.UserProvider
logger:
zap-config:
level: info
2.引入傳輸結(jié)構(gòu),定義服務(wù)以及方法名映射
type UserProvider struct {
}
func (u *UserProvider) GetUser(ctx context.Context, req int32) (*User, error) {
var err error
logger.Infof("req:%#v", req)
user := &User{}
user.ID = strconv.Itoa(int(req))
return user, err
}
// MethodMapper 定義方法名映射,從 Go 的方法名映射到 Java 小寫(xiě)方法名,只有 dubbo 協(xié)議服務(wù)接口才需要使用
func (s *UserProvider) MethodMapper() map[string]string {
return map[string]string{
"GetUser": "getUser",
}
}
func init(){
config.SetProviderService(&pkg.UserProvider{})
}
3.啟動(dòng)服務(wù)
// export DUBBO_GO_CONFIG_PATH=dubbogo.yml
func main() {
if err := config.Load(); err != nil {
panic(err)
}
select {}
}
1.Java 客戶(hù)端 Spring 配置
resources/META-INF.spring/dubbo.consumer.xml<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- 消費(fèi)方應(yīng)用名,用于計(jì)算依賴(lài)關(guān)系,不是匹配條件,不要與提供方一樣 -->
<dubbo:application name="user-info-client" />
<!-- 連接到哪個(gè)本地注冊(cè)中心 -->
<dubbo:registry id="dubbogo" address="zookeeper://127.0.0.1:2181" />
<!-- dubbo.registry.address from dubbo.properties -->
<!-- dubbo:registry address="${dubbo.registry.address}" / -->
<!-- 用dubbo協(xié)議在20880端口暴露服務(wù) -->
<dubbo:protocol id="dubbo" name="dubbo" />
<!-- 聲明需要使用的服務(wù)接口 -->
<dubbo:reference registry="dubbogo" check="false" id="userProvider" protocol="dubbo" interface="org.apache.dubbo.UserProvider">
<!--<dubbo:parameter key="heartbeat" value="10000"/ -->
</dubbo:reference>
<dubbo:reference registry="dubbogo" check="false" id="userProvider1" protocol="dubbo" version="2.0" interface="org.apache.dubbo.UserProvider">
</dubbo:reference>
<dubbo:reference registry="dubbogo" check="false" id="userProvider2" protocol="dubbo" version="2.0" group="as" interface="org.apache.dubbo.UserProvider">
</dubbo:reference>
</beans>
2.發(fā)起調(diào)用
public class Consumer {
// Define a private variable (Required in Spring)
private static UserProvider userProvider;
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo.consumer.xml"});
userProvider = (UserProvider)context.getBean("userProvider");
testGetUser();
}
private static void testGetUser() throws Exception {
User user = userProvider.getUser(1);
System.out.println(user.getId());
}
}
更多建議: