W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
服務(wù)是 Dubbo 中的核心概念,一個服務(wù)代表一組 RPC 方法的集合,服務(wù)是面向用戶編程、服務(wù)發(fā)現(xiàn)機(jī)制等的基本單位。Dubbo 開發(fā)的基本流程是:用戶定義 RPC 服務(wù),通過約定的配置 方式將 RPC 聲明為 Dubbo 服務(wù),然后就可以基于服務(wù) API 進(jìn)行編程了。對服務(wù)提供者來說是提供 RPC 服務(wù)的具體實現(xiàn),而對服務(wù)消費(fèi)者來說則是使用特定數(shù)據(jù)發(fā)起服務(wù)調(diào)用。
下面從定義服務(wù)、編譯服務(wù)、配置并加載服務(wù)三個方面說明如何快速的開發(fā) Dubbo 服務(wù)。
Dubbo3 推薦使用 IDL 定義跨語言服務(wù),如您更習(xí)慣使用特定語言的服務(wù)定義方式,請移步多語言模塊。
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 定義服務(wù)的一個簡單示例,我們可以把它命名為 ?DemoService.proto
?,proto 文件中定義了 RPC 服務(wù)名稱 ?DemoService
?與方法簽名 ?SayHello (HelloRequest) returns (HelloReply) {}
?,同時還定義了方法的入?yún)⒔Y(jié)構(gòu)體、出參結(jié)構(gòu)體 ?HelloRequest
?與 ?HelloReply
?。
IDL 格式的服務(wù)依賴 Protobuf 編譯器,用來生成可以被用戶調(diào)用的客戶端與服務(wù)端編程 API,Dubbo 在原生 Protobuf Compiler 的基礎(chǔ)上提供了適配多種語言的特有插件,用于適配 Dubbo 框架特有的 API 與編程模型。
使用 Dubbo3 IDL 定義的服務(wù)只允許一個入?yún)⑴c出參,這種形式的服務(wù)簽名有兩個優(yōu)勢,一是對多語言實現(xiàn)更友好,二是可以保證服務(wù)的向后兼容性,依賴于 Protobuf 序列化的兼容性,我們可以很容易的調(diào)整傳輸?shù)臄?shù)據(jù)結(jié)構(gòu)如增、刪字段等,完全不用擔(dān)心接口的兼容性。
根據(jù)當(dāng)前采用的語言,配置相應(yīng)的 Protobuf 插件,編譯后將生產(chǎn)語言相關(guān)的服務(wù)定義 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)
}
提供端負(fù)責(zé)提供具體的 Dubbo 服務(wù)實現(xiàn),也就是遵循 RPC 簽名所約束的格式,去實現(xiàn)具體的業(yè)務(wù)邏輯代碼。在實現(xiàn)服務(wù)之后,要將服務(wù)實現(xiàn)注冊為標(biāo)準(zhǔn)的 Dubbo 服務(wù), 之后 Dubbo 框架就能根據(jù)接收到的請求轉(zhuǎn)發(fā)給服務(wù)實現(xiàn),執(zhí)行方法,并將結(jié)果返回。
消費(fèi)端的配置會更簡單一些,只需要聲明 IDL 定義的服務(wù)為標(biāo)準(zhǔn)的 Dubbo 服務(wù),框架就可以幫助開發(fā)者生成相應(yīng)的 proxy,開發(fā)者將完全面向 proxy 編程, 基本上 Dubbo 所有語言的實現(xiàn)都保證了 proxy 依據(jù) IDL 服務(wù)定義暴露標(biāo)準(zhǔn)化的接口。
提供端,實現(xiàn)服務(wù)
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));
}
}
提供端,注冊服務(wù)(以 Spring XML 為例)
<bean id="demoServiceImpl" class="org.apache.dubbo.demo.provider.DemoServiceImpl"/>
<dubbo:service serialization="protobuf" interface="org.apache.dubbo.demo.DemoService" ref="demoServiceImpl"/>
消費(fèi)端,引用服務(wù)
<dubbo:reference scope="remote" id="demoService" check="false" interface="org.apache.dubbo.demo.DemoService"/>
消費(fèi)端,使用服務(wù) 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)服務(wù)
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))
}
消費(fèi)端,使用服務(wù) 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)系方式:
更多建議: