好久没写东西了,今年实在太忙,基本都在搞业务开发,晚上来补一篇,作为今年的收官博客。google-rpc 正式发布以来,受到了不少人的关注,这么知名的rpc框架,不集成到dubbox中有点说不过去。

但是grpc的思路与其它rpc(比如:avro/thrift)有些不一样,并非直接采用 "接口定义+服务实现"的套路,而是采用了"抽象类派生"的做法,见下面的示例:

 syntax = "proto3";

 option java_multiple_files = true;
option java_package = "com.cnblogs.yjmyzz.demo.service.api.grpc";
option java_outer_classname = "GrpcHelloServiceProto"; package hello; service GrpcHelloService {
rpc ping (PingRequest) returns (PingResponse) {}
} message PingRequest{} message PingResponse {
string message = 1;
}

这是一段protobuf的定义文件,最终生成的java代码为:

 package com.cnblogs.yjmyzz.demo.service.api.grpc;

 import static io.grpc.stub.ClientCalls.asyncUnaryCall;
import static io.grpc.stub.ClientCalls.asyncServerStreamingCall;
import static io.grpc.stub.ClientCalls.asyncClientStreamingCall;
import static io.grpc.stub.ClientCalls.asyncBidiStreamingCall;
import static io.grpc.stub.ClientCalls.blockingUnaryCall;
import static io.grpc.stub.ClientCalls.blockingServerStreamingCall;
import static io.grpc.stub.ClientCalls.futureUnaryCall;
import static io.grpc.MethodDescriptor.generateFullMethodName;
import static io.grpc.stub.ServerCalls.asyncUnaryCall;
import static io.grpc.stub.ServerCalls.asyncServerStreamingCall;
import static io.grpc.stub.ServerCalls.asyncClientStreamingCall;
import static io.grpc.stub.ServerCalls.asyncBidiStreamingCall;
import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall;
import static io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall; /**
*/
@javax.annotation.Generated(
value = "by gRPC proto compiler (version 1.0.1)",
comments = "Source: hello.proto")
public class GrpcHelloServiceGrpc { private GrpcHelloServiceGrpc() {} public static final String SERVICE_NAME = "hello.GrpcHelloService"; // Static method descriptors that strictly reflect the proto.
@io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/1901")
public static final io.grpc.MethodDescriptor<com.cnblogs.yjmyzz.demo.service.api.grpc.PingRequest,
com.cnblogs.yjmyzz.demo.service.api.grpc.PingResponse> METHOD_PING =
io.grpc.MethodDescriptor.create(
io.grpc.MethodDescriptor.MethodType.UNARY,
generateFullMethodName(
"hello.GrpcHelloService", "ping"),
io.grpc.protobuf.ProtoUtils.marshaller(com.cnblogs.yjmyzz.demo.service.api.grpc.PingRequest.getDefaultInstance()),
io.grpc.protobuf.ProtoUtils.marshaller(com.cnblogs.yjmyzz.demo.service.api.grpc.PingResponse.getDefaultInstance())); /**
* Creates a new async stub that supports all call types for the service
*/
public static GrpcHelloServiceStub newStub(io.grpc.Channel channel) {
return new GrpcHelloServiceStub(channel);
} /**
* Creates a new blocking-style stub that supports unary and streaming output calls on the service
*/
public static GrpcHelloServiceBlockingStub newBlockingStub(
io.grpc.Channel channel) {
return new GrpcHelloServiceBlockingStub(channel);
} /**
* Creates a new ListenableFuture-style stub that supports unary and streaming output calls on the service
*/
public static GrpcHelloServiceFutureStub newFutureStub(
io.grpc.Channel channel) {
return new GrpcHelloServiceFutureStub(channel);
} /**
*/
public static abstract class GrpcHelloServiceImplBase implements io.grpc.BindableService { /**
*/
public void ping(com.cnblogs.yjmyzz.demo.service.api.grpc.PingRequest request,
io.grpc.stub.StreamObserver<com.cnblogs.yjmyzz.demo.service.api.grpc.PingResponse> responseObserver) {
asyncUnimplementedUnaryCall(METHOD_PING, responseObserver);
} @java.lang.Override public io.grpc.ServerServiceDefinition bindService() {
return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor())
.addMethod(
METHOD_PING,
asyncUnaryCall(
new MethodHandlers<
com.cnblogs.yjmyzz.demo.service.api.grpc.PingRequest,
com.cnblogs.yjmyzz.demo.service.api.grpc.PingResponse>(
this, METHODID_PING)))
.build();
}
} /**
*/
public static final class GrpcHelloServiceStub extends io.grpc.stub.AbstractStub<GrpcHelloServiceStub> {
private GrpcHelloServiceStub(io.grpc.Channel channel) {
super(channel);
} private GrpcHelloServiceStub(io.grpc.Channel channel,
io.grpc.CallOptions callOptions) {
super(channel, callOptions);
} @java.lang.Override
protected GrpcHelloServiceStub build(io.grpc.Channel channel,
io.grpc.CallOptions callOptions) {
return new GrpcHelloServiceStub(channel, callOptions);
} /**
*/
public void ping(com.cnblogs.yjmyzz.demo.service.api.grpc.PingRequest request,
io.grpc.stub.StreamObserver<com.cnblogs.yjmyzz.demo.service.api.grpc.PingResponse> responseObserver) {
asyncUnaryCall(
getChannel().newCall(METHOD_PING, getCallOptions()), request, responseObserver);
}
} /**
*/
public static final class GrpcHelloServiceBlockingStub extends io.grpc.stub.AbstractStub<GrpcHelloServiceBlockingStub> {
private GrpcHelloServiceBlockingStub(io.grpc.Channel channel) {
super(channel);
} private GrpcHelloServiceBlockingStub(io.grpc.Channel channel,
io.grpc.CallOptions callOptions) {
super(channel, callOptions);
} @java.lang.Override
protected GrpcHelloServiceBlockingStub build(io.grpc.Channel channel,
io.grpc.CallOptions callOptions) {
return new GrpcHelloServiceBlockingStub(channel, callOptions);
} /**
*/
public com.cnblogs.yjmyzz.demo.service.api.grpc.PingResponse ping(com.cnblogs.yjmyzz.demo.service.api.grpc.PingRequest request) {
return blockingUnaryCall(
getChannel(), METHOD_PING, getCallOptions(), request);
}
} /**
*/
public static final class GrpcHelloServiceFutureStub extends io.grpc.stub.AbstractStub<GrpcHelloServiceFutureStub> {
private GrpcHelloServiceFutureStub(io.grpc.Channel channel) {
super(channel);
} private GrpcHelloServiceFutureStub(io.grpc.Channel channel,
io.grpc.CallOptions callOptions) {
super(channel, callOptions);
} @java.lang.Override
protected GrpcHelloServiceFutureStub build(io.grpc.Channel channel,
io.grpc.CallOptions callOptions) {
return new GrpcHelloServiceFutureStub(channel, callOptions);
} /**
*/
public com.google.common.util.concurrent.ListenableFuture<com.cnblogs.yjmyzz.demo.service.api.grpc.PingResponse> ping(
com.cnblogs.yjmyzz.demo.service.api.grpc.PingRequest request) {
return futureUnaryCall(
getChannel().newCall(METHOD_PING, getCallOptions()), request);
}
} private static final int METHODID_PING = 0; private static class MethodHandlers<Req, Resp> implements
io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,
io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,
io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,
io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {
private final GrpcHelloServiceImplBase serviceImpl;
private final int methodId; public MethodHandlers(GrpcHelloServiceImplBase serviceImpl, int methodId) {
this.serviceImpl = serviceImpl;
this.methodId = methodId;
} @java.lang.Override
@java.lang.SuppressWarnings("unchecked")
public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {
switch (methodId) {
case METHODID_PING:
serviceImpl.ping((com.cnblogs.yjmyzz.demo.service.api.grpc.PingRequest) request,
(io.grpc.stub.StreamObserver<com.cnblogs.yjmyzz.demo.service.api.grpc.PingResponse>) responseObserver);
break;
default:
throw new AssertionError();
}
} @java.lang.Override
@java.lang.SuppressWarnings("unchecked")
public io.grpc.stub.StreamObserver<Req> invoke(
io.grpc.stub.StreamObserver<Resp> responseObserver) {
switch (methodId) {
default:
throw new AssertionError();
}
}
} public static io.grpc.ServiceDescriptor getServiceDescriptor() {
return new io.grpc.ServiceDescriptor(SERVICE_NAME,
METHOD_PING);
} }

其中:

  public static abstract class GrpcHelloServiceImplBase implements io.grpc.BindableService {

    /**
*/
public void ping(com.cnblogs.yjmyzz.demo.service.api.grpc.PingRequest request,
io.grpc.stub.StreamObserver<com.cnblogs.yjmyzz.demo.service.api.grpc.PingResponse> responseObserver) {
asyncUnimplementedUnaryCall(METHOD_PING, responseObserver);
} @java.lang.Override public io.grpc.ServerServiceDefinition bindService() {
return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor())
.addMethod(
METHOD_PING,
asyncUnaryCall(
new MethodHandlers<
com.cnblogs.yjmyzz.demo.service.api.grpc.PingRequest,
com.cnblogs.yjmyzz.demo.service.api.grpc.PingResponse>(
this, METHODID_PING)))
.build();
}
}

就是一个抽象类,而且调用时要借助stub来实现,而stub的生成,又要借助channel,所以在集成到dubbox中时,要花点心思。 

先定义一个辅助接口:

package com.alibaba.dubbo.rpc.protocol.grpc;

import io.grpc.BindableService;
import io.grpc.Channel; /**
* Created by yangjunming on 16/10/7.
*/
public interface GrpcBindableService extends BindableService { Channel getChannel(); void setChannel(Channel channel);
}

这个接口的目的,是为了最终调用时,能拿到channel,进而生成stub.

然后在实现具体gprc服务时,实现这个接口:

package com.cnblogs.yjmyzz.demo.service.impl.grpc;

import com.alibaba.dubbo.rpc.protocol.grpc.GrpcBindableService;
import com.cnblogs.yjmyzz.demo.service.api.grpc.GrpcHelloServiceGrpc;
import com.cnblogs.yjmyzz.demo.service.api.grpc.PingRequest;
import com.cnblogs.yjmyzz.demo.service.api.grpc.PingResponse;
import io.grpc.Channel;
import io.grpc.stub.StreamObserver;
import org.springframework.stereotype.Service; /**
* Created by yangjunming on 2016/11/3.
*/
@Service("grpcService")
public class HelloServiceImpl extends GrpcHelloServiceGrpc.GrpcHelloServiceImplBase implements GrpcBindableService { private Channel channel; public Channel getChannel() {
return channel;
} public void setChannel(Channel channel) {
this.channel = channel;
} @Override
public void ping(PingRequest request,
StreamObserver<PingResponse> responseObserver) {
PingResponse reply = PingResponse.newBuilder().setMessage("grpc is running").build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}

这样处理后,dubbox中添加grpc的协议就方便了:

package com.alibaba.dubbo.rpc.protocol.grpc;

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.protocol.AbstractProxyProtocol;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Server;
import io.grpc.ServerBuilder; import java.io.IOException; /**
* 为dubbo-rpc添加"google-gRPC"支持
* by 杨俊明(http://yjmyzz.cnblogs.com/)
*/
public class GrpcProtocol extends AbstractProxyProtocol {
public static final int DEFAULT_PORT = 50051;
private static final Logger logger = LoggerFactory.getLogger(GrpcProtocol.class); public int getDefaultPort() {
return DEFAULT_PORT;
} public GrpcProtocol() {
super(IOException.class, RpcException.class);
} @Override
protected <T> Runnable doExport(T impl, Class<T> type, URL url)
throws RpcException { logger.info("impl => " + impl.getClass());
logger.info("type => " + type.getName());
logger.info("url => " + url); try {
String clsName = url.getParameter("class");
Class<?> cls = Class.forName(clsName);
GrpcBindableService service = (GrpcBindableService) cls.newInstance();
final Server grpcServer = ServerBuilder.forPort(url.getPort())
.addService(service)
.build()
.start();
logger.info("grpc server started !");
return new Runnable() {
public void run() {
try {
logger.info("Close gRPC Server");
grpcServer.shutdown();
} catch (Throwable e) {
logger.warn(e.getMessage(), e);
}
}
};
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new RpcException(e.getMessage(), e);
}
} @Override
protected <T> T doRefer(Class<T> type, URL url) throws RpcException {
logger.info("type => " + type.getName());
logger.info("url => " + url);
final ManagedChannel channel = ManagedChannelBuilder.forAddress(url.getHost(), url.getPort())
.usePlaintext(true)
.build();
try {
DefaultBindableService service = new DefaultBindableService();
service.setChannel(channel);
return (T) service;
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new RpcException(e.getMessage(), e);
}
} }

在doExport暴露grpc服务时,通过类型转换成我们刚才定义的接口GrpcBindableService,解决了grpc服务的启动问题。

再来看如何引用这个服务,此为还要再定义一个辅助类:

package com.alibaba.dubbo.rpc.protocol.grpc;

import io.grpc.Channel;
import io.grpc.ServerServiceDefinition; /**
* Created by yangjunming on 16/10/7.
*/
public class DefaultBindableService implements GrpcBindableService { private Channel channel; @Override
public Channel getChannel() {
return channel;
} @Override
public void setChannel(Channel channel) {
this.channel = channel;
} @Override
public ServerServiceDefinition bindService() {
return null;
}
}

这个类就是刚才定义的新接口GrpcBindableService的默认实现,目的是为了能将生成的channel通过setter方法保存下来。doRefer方法利用这个类,拿到了channel,最终给到grpc服务的调用方。

客户端调用示例:

    private static void testGrpc(ConfigurableApplicationContext ctx) throws InterruptedException {
GrpcBindableService service = ctx.getBean(GrpcBindableService.class, "grpcService");
AbstractStub stub = GrpcHelloServiceGrpc.newBlockingStub(service.getChannel());
PingRequest request = PingRequest.newBuilder().build();
logger.info("\n---------gprc协议测试开始---------");
logger.info(stub.getClass().toString());
PingResponse response = ((GrpcHelloServiceGrpc.GrpcHelloServiceBlockingStub) stub).ping(request);
logger.info("\tping=>" + response.getMessage());
((ManagedChannel) stub.getChannel()).shutdown().awaitTermination(5, TimeUnit.SECONDS);
}

完整示例代码请参考github上我重写的dubbo-demo示例

最后:祝大家圣诞快乐!

dubbox 增加google-gprc/protobuf支持的更多相关文章

  1. dubbo/dubbox 增加原生thrift及avro支持

    (facebook) thrift / (hadoop) avro / (google) probuf(grpc)是近几年来比较抢眼的高效序列化/rpc框架,dubbo框架虽然有thrift的支持,但 ...

  2. Netty使用Google的ProtoBuf

    protobuf是由Google开发的一套对数据结构进行序列化的方法,可用做通信协议,数据存储格式,等等.其特点是不限语言.不限平台.扩展性强 Netty也提供了对Protobuf的天然支持,我们今天 ...

  3. php增加对mysqli的支持

    php增加对mysqli的支持   我在fedora下使用yum安装的php和mysql,但是发现php不支持myslqi,只能编译一个mysqli的扩展给php用了. 方法如下: 1.下载php 2 ...

  4. HTTP实现长连接(TTP1.1和HTTP1.0相比较而言,最大的区别就是增加了持久连接支持Connection: keep-alive)

    HTTP实现长连接 HTTP是无状态的 也就是说,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接.如果客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web ...

  5. 在ASP.NET Core Web API中为RESTful服务增加对HAL的支持

    HAL(Hypertext Application Language,超文本应用语言)是一种RESTful API的数据格式风格,为RESTful API的设计提供了接口规范,同时也降低了客户端与服务 ...

  6. google的protobuf简单介绍

    google的protobuf是一种轻便高效的结构化数据存储格式,在通信协议和数据存储等领域中使用比较多.protobuf对于结构中的每个成员,会提供set系列函数和get系列函数. 但是,对于使用来 ...

  7. Protobuf支持 pointf

    Protobuf支持 pointf序列化 加入:ProtoBuf.Meta.RuntimeTypeModel.Default.Add(typeof(System.Drawing.PointF), fa ...

  8. MyEclipse6.5增加对Tomcat7的支持

    MyEclipse6.5增加对Tomcat7的支持 最近在研究Servlet3.0,它是JavaEE6.0规范中的一部分 而Servlet3.0对服务器是有要求的,比如Tomcat7+(而Tomcat ...

  9. 使用PaxScript为Delphi应用增加对脚本的支持

    通过使用PaxScript可以为Delphi应用增加对脚本的支持. PaxScript支持paxC,paxBasic,paxPascle,paxJavaScript(对ECMA-262做了扩展) 四种 ...

  10. 开源即时通讯GGTalk 8.0发布,增加Linux客户端,支持在统信UOS、银河麒麟上运行!

    GGTalk在2021年推出7.0后,经过一年多时间的开发,终于推出8.0版本,实现了Linux客户端. 这几年,信创国产化的势头越来越猛,政府事企业单位都在逐步转向使用国产OS.国产CPU.国产数据 ...

随机推荐

  1. 【基于WPF+OneNote+Oracle的中文图片识别系统阶段总结】之篇四:关于OneNote入库处理以及审核

    篇一:WPF常用知识以及本项目设计总结:http://www.cnblogs.com/baiboy/p/wpf.html 篇二:基于OneNote难点突破和批量识别:http://www.cnblog ...

  2. Spring Bean的生命周期(非常详细)

    Spring作为当前Java最流行.最强大的轻量级框架,受到了程序员的热烈欢迎.准确的了解Spring Bean的生命周期是非常必要的.我们通常使用ApplicationContext作为Spring ...

  3. H5实现本地预览图片

    我们使用H5可以很容易的实现图片上传前对其进行预览的功能 Html代码如下: <!DOCTYPE html> <html lang="en"> <he ...

  4. 给 DevOps 初学者的入门指南

    当我们谈到 DevOps 时,可能讨论的是:流程和管理,运维和自动化,架构和服务,以及文化和组织等等概念.那么,到底什么是"DevOps"呢? 什么是DevOps 随着软件发布迭代 ...

  5. 使用F#开发ASP.NET Core应用程序

    .NET Core 里的F# 在.NET Core刚发布时,就已经添加了对F#的支持.但因为当时F#组件还不完整,而一些依赖包并没有放在Nuget上,而是社区自己放到MyGet上,所以在使用dotne ...

  6. C++泛型编程:template模板

    泛型编程就是以独立于任何特定类型的方式编写代码,而模板是C++泛型编程的基础. 所谓template,是针对“一个或多个尚未明确的类型”所编写的函数或类. 使用template时,可以显示的或隐示的将 ...

  7. Android手机越用越卡?

    一直不懂Android手机为什么会越用越卡,而ios就几乎能一直保持流畅度.后来发现这个锅不该google背,而是国内混乱的Android软件开发商的锅.主要是Android对应用没什么限制,而goo ...

  8. ASP.NET MVC——URL路由

    在MVC之前,ASP.NET假设请求的URL与服务器上的文件之间有关联,服务器接受请求,并输出相应的文件.而在引入MVC后,请求是由控制器的动作方法来处理的.为了处理URL,便引入了路由系统. 首先我 ...

  9. 来玩Play框架01 简介

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 说到网络框架,Ruby的Ruby on Rail和Python的Django都相当 ...

  10. 关于i++引出的线程不安全性的分析以及解决措施

    Q:i++是线程安全的吗? A:如果是局部变量,那么i++是线程安全. 如果是全局变量,那么i++不是线程安全的. 理由:如果是局部变量,那么i++是线程安全:局部变量其他线程访问不到,所以根本不存在 ...