W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
服務是 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 語言生成的 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);
}
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 服務定義暴露標準化的接口。
提供端,實現(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());
}
提供端,實現(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)
}
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: