Dubbo3 快速開始

2022-03-29 11:42 更新

服務是 Dubbo 中的核心概念,一個服務代表一組 RPC 方法的集合,服務是面向用戶編程、服務發(fā)現(xiàn)機制等的基本單位。Dubbo 開發(fā)的基本流程是:用戶定義 RPC 服務,通過約定的配置 方式將 RPC 聲明為 Dubbo 服務,然后就可以基于服務 API 進行編程了。對服務提供者來說是提供 RPC 服務的具體實現(xiàn),而對服務消費者來說則是使用特定數(shù)據(jù)發(fā)起服務調(diào)用。

下面從定義服務、編譯服務、配置并加載服務三個方面說明如何快速的開發(fā) Dubbo 服務。

定義服務

Dubbo3 推薦使用 IDL 定義跨語言服務,如您更習慣使用特定語言的服務定義方式,請移步多語言模塊。

syntax = "proto3";

option java_multiple_files = true;
option java_package = "org.apache.dubbo.demo";
option java_outer_classname = "DemoServiceProto";
option objc_class_prefix = "DEMOSRV";

package demoservice;

// The demo service definition.
service DemoService {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

以上是使用 IDL 定義服務的一個簡單示例,我們可以把它命名為 ?DemoService.proto?,proto 文件中定義了 RPC 服務名稱 ?DemoService ?與方法簽名 ?SayHello (HelloRequest) returns (HelloReply) {}?,同時還定義了方法的入?yún)⒔Y(jié)構(gòu)體、出參結(jié)構(gòu)體 ?HelloRequest ?與 ?HelloReply?。 IDL 格式的服務依賴 Protobuf 編譯器,用來生成可以被用戶調(diào)用的客戶端與服務端編程 API,Dubbo 在原生 Protobuf Compiler 的基礎上提供了適配多種語言的特有插件,用于適配 Dubbo 框架特有的 API 與編程模型。

使用 Dubbo3 IDL 定義的服務只允許一個入?yún)⑴c出參,這種形式的服務簽名有兩個優(yōu)勢,一是對多語言實現(xiàn)更友好,二是可以保證服務的向后兼容性,依賴于 Protobuf 序列化的兼容性,我們可以很容易的調(diào)整傳輸?shù)臄?shù)據(jù)結(jié)構(gòu)如增、刪字段等,完全不用擔心接口的兼容性。

編譯服務

根據(jù)當前采用的語言,配置相應的 Protobuf 插件,編譯后將生產(chǎn)語言相關的服務定義 stub。

Java

Java 語言生成的 stub 如下,核心是一個接口定義

@javax.annotation.Generated(
value = "by Dubbo generator",
comments = "Source: DemoService.proto")
public interface DemoService {
    static final String JAVA_SERVICE_NAME = "org.apache.dubbo.demo.DemoService";
    static final String SERVICE_NAME = "demoservice.DemoService";

    org.apache.dubbo.demo.HelloReply sayHello(org.apache.dubbo.demo.HelloRequest request);

    CompletableFuture<org.apache.dubbo.demo.HelloReply> sayHelloAsync(org.apache.dubbo.demo.HelloRequest request);
}

Golang

Go 語言生成的 stub 如下,這個 stub 里存了用戶定義的接口和數(shù)據(jù)的類型。

func _DUBBO_Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(HelloRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	base := srv.(dgrpc.Dubbo3GrpcService)
	args := []interface{}{}
	args = append(args, in)
	invo := invocation.NewRPCInvocation("SayHello", args, nil)
	if interceptor == nil {
		result := base.GetProxyImpl().Invoke(ctx, invo)
		return result.Result(), result.Error()
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/main.Greeter/SayHello",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		result := base.GetProxyImpl().Invoke(context.Background(), invo)
		return result.Result(), result.Error()
	}
	return interceptor(ctx, in, info, handler)
}

配置并加載服務

提供端負責提供具體的 Dubbo 服務實現(xiàn),也就是遵循 RPC 簽名所約束的格式,去實現(xiàn)具體的業(yè)務邏輯代碼。在實現(xiàn)服務之后,要將服務實現(xiàn)注冊為標準的 Dubbo 服務, 之后 Dubbo 框架就能根據(jù)接收到的請求轉(zhuǎn)發(fā)給服務實現(xiàn),執(zhí)行方法,并將結(jié)果返回。

消費端的配置會更簡單一些,只需要聲明 IDL 定義的服務為標準的 Dubbo 服務,框架就可以幫助開發(fā)者生成相應的 proxy,開發(fā)者將完全面向 proxy 編程, 基本上 Dubbo 所有語言的實現(xiàn)都保證了 proxy 依據(jù) IDL 服務定義暴露標準化的接口。

Java

提供端,實現(xiàn)服務

public class DemoServiceImpl implements DemoService {
    private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);

    @Override
    public HelloReply sayHello(HelloRequest request) {
        logger.info("Hello " + request.getName() + ", request from consumer: " + RpcContext.getContext().getRemoteAddress());
        return HelloReply.newBuilder()
                .setMessage("Hello " + request.getName() + ", response from provider: "
                        + RpcContext.getContext().getLocalAddress())
                .build();
    }

    @Override
    public CompletableFuture<HelloReply> sayHelloAsync(HelloRequest request) {
        return CompletableFuture.completedFuture(sayHello(request));
    }
}

提供端,注冊服務(以 Spring XML 為例)

<bean id="demoServiceImpl" class="org.apache.dubbo.demo.provider.DemoServiceImpl"/>
<dubbo:service serialization="protobuf" interface="org.apache.dubbo.demo.DemoService" ref="demoServiceImpl"/>

消費端,引用服務

<dubbo:reference scope="remote" id="demoService" check="false" interface="org.apache.dubbo.demo.DemoService"/>

消費端,使用服務 proxy

public void callService() throws Exception {
    ...
    DemoService demoService = context.getBean("demoService", DemoService.class);
    HelloRequest request = HelloRequest.newBuilder().setName("Hello").build();
    HelloReply reply = demoService.sayHello(request);
    System.out.println("result: " + reply.getMessage());
}

Golang

提供端,實現(xiàn)服務

type User struct {
	ID   string
	Name string
	Age  int32
	Time time.Time
}

type UserProvider struct {
}

func (u *UserProvider) GetUser(ctx context.Context, req []interface{}) (*User, error) {
	gxlog.CInfo("req:%#v", req)
	rsp := User{"A001", "Alex Stocks", 18, time.Now()}
	gxlog.CInfo("rsp:%#v", rsp)
	return &rsp, nil
}

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

func (u User) JavaClassName() string {
	return "org.apache.dubbo.User"
}

func main() {
    hessian.RegisterPOJO(&User{})
	config.SetProviderService(new(UserProvider))
}

消費端,使用服務 proxy

func main() {
	config.Load()
	user := &pkg.User{}
	err := userProvider.GetUser(context.TODO(), []interface{}{"A001"}, user)
	if err != nil {
		os.Exit(1)
		return
	}
	gxlog.CInfo("response result: %v\n", user)
}

查看完整示例


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號