JDK 8,Golang >= 1.15,Dubbo 3.0.2,zookeeper 啟動,
// 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 文件自動生成)
type GreeterClientImpl struct {
// Sends a greeting
SayHello func(ctx context.Context, in *HelloRequest) (*User, error)
}
Go server (由開發(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 用戶服務(wù)接口定義規(guī)范
references:
GreeterClientImpl:
protocol: tri
interface: com.apache.dubbo.sample.basic.IGreeter # must be compatible with grpc or dubbo-java
group: dubbogo # 需要與服務(wù)端對應(yīng) 默認(rèn)為空
version: v1.0.1 # 需要與服務(wù)端對應(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ù)端對應(yīng) 默認(rèn)為空
version: v1.0.1 # 需要與服務(wù)端對應(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;
}
該接口描述文件定義了將會生成的 Java 類 org.apache.dubbo.sample.hello.Helloworld,以及類中包含的傳輸結(jié)構(gòu) HelloRequest 和 User 類。
package com.apache.dubbo.sample.basic;
// 引入根據(jù) PB 生成的類
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 作為注冊中心
service.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181"));
service.export();
System.out.println("dubbo service started");
new CountDownLatch(1).await();
}
}
啟動服務(wù),可看到輸出如下日志,代表 Java Triple Server 啟動成功
main INFO bootstrap.DubboBootstrap: [DUBBO] DubboBootstrap has started., dubbo version: 3.0.2, current host: 192.168.0.108
dubbo service started
對于已經(jīng)啟動的Dubbo服務(wù),如需要開發(fā)與其對應(yīng)的Go-client,需要進行如下步驟:
1.編寫與 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.撰寫配置文件: 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.撰寫 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.啟動服務(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 快速開始
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.實現(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 啟動
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.通過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"/>
<!-- 連接到哪個本地注冊中心 -->
<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>
啟動Provider類,可看到輸出如下日志,代表 Dubbo Server 啟動成功
[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
對于已經(jīng)啟動的Dubbo服務(wù),如需要開發(fā)與其對應(yīng)的Go-client,需要進行如下步驟:
1.編寫與 Java 適配的 POJO 類 User
import(
hessian "github.com/apache/dubbo-go-hessian2"
)
// 字段需要與 Java 側(cè)對應(yīng),首字母大寫
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 類名對應(yīng)
}
func init(){
hessian.RegisterPOJO(&pkg.User{}) // 注冊 POJO
}
2.編寫與 Java 側(cè)一致的客戶端存根類,其接口方法需要與Java側(cè)對應(yīng)規(guī)定第一個參數(shù)必須為 context.Context,最后一個返回值必須為 error
import(
"dubbo.apache.org/dubbo-go/v3/config"
)
var (
userProvider = &pkg.UserProvider{}
)
// UserProvider 客戶端存根類
type UserProvider struct {
// dubbo標(biāo)簽,用于適配go側(cè)客戶端大寫方法名 -> java側(cè)小寫方法名,只有 dubbo 協(xié)議客戶端才需要使用
GetUser func(ctx context.Context, req int32) (*User, error) `dubbo:"getUser"`
}
func init(){
// 注冊客戶端存根類到框架,實例化客戶端接口指針 userProvider
config.SetConsumerService(userProvider)
}
3.撰寫配置文件: dubbogo.yml
dubbo:
registries:
demoZK: # 定義注冊中心ID
protocol: zookeeper
timeout: 3s
address: 127.0.0.1:2181
consumer:
references:
UserProvider: # 存根類名
protocol: dubbo # dubbo 協(xié)議,默認(rèn) hessian2 序列化方式
interface: org.apache.dubbo.UserProvider # 接口需要與Java側(cè)對應(yīng)
logger:
zap-config:
level: info # 日志級別
或者使用Triple + Hessian2 序列化請求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 序列化,不配置會報錯
interface: org.apache.dubbo.UserProvider
logger:
zap-config:
level: info
4.撰寫 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 小寫方法名,只有 dubbo 協(xié)議服務(wù)接口才需要使用
func (s *UserProvider) MethodMapper() map[string]string {
return map[string]string{
"GetUser": "getUser",
}
}
func init(){
config.SetProviderService(&pkg.UserProvider{})
}
3.啟動服務(wù)
// export DUBBO_GO_CONFIG_PATH=dubbogo.yml
func main() {
if err := config.Load(); err != nil {
panic(err)
}
select {}
}
1.Java 客戶端 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">
<!-- 消費方應(yīng)用名,用于計算依賴關(guān)系,不是匹配條件,不要與提供方一樣 -->
<dubbo:application name="user-info-client" />
<!-- 連接到哪個本地注冊中心 -->
<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());
}
}
更多建議: