我们是怎么实现Grpc CodeFirst

简介:

我们是怎么实现Grpc CodeFirst
前言:

Grpc默认是ProtoFirst的,即先写 proto文件,再生成代码,需要人工维护proto,生成的代码也不友好,所以出现了Grpc CodeFirst,下面来说说我们是怎么实现Grpc CodeFirst

目录:

实现和WCF一样的CodeFirst

(1). 实现Grpc CodeFirst,  简化WCF一定要抽取接口的问题

(2). 通过代码生成proto和注释,给第三方语言使用

(3). 实现Grpc DashBoard,用于Http远程调用和管理

(4). 实现服务注册与发现

(5). 实现分布式日志跟踪

(6). 日志监控等等

我们是怎么实现Grpc CodeFirst

1.要实现CodeFirst先要了解ProtoFirst生成的代码,下面我截了部分生成代码

(1).关键是这个BindService,用于把实现的Grpc方法绑定到GrpcServiceDefinition

public static partial class Greeter
{

static readonly string __ServiceName = "helloworld.Greeter";

static readonly grpc::Marshaller<global::Helloworld.HelloRequest> __Marshaller_helloworld_HelloRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Helloworld.HelloRequest.Parser.ParseFrom);
static readonly grpc::Marshaller<global::Helloworld.HelloReply> __Marshaller_helloworld_HelloReply = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Helloworld.HelloReply.Parser.ParseFrom);

static readonly grpc::Method<global::Helloworld.HelloRequest, global::Helloworld.HelloReply> __Method_SayHello = new grpc::Method<global::Helloworld.HelloRequest, global::Helloworld.HelloReply>(
    grpc::MethodType.Unary,
    __ServiceName,
    "SayHello",
    __Marshaller_helloworld_HelloRequest,
    __Marshaller_helloworld_HelloReply);

static readonly grpc::Method<global::Helloworld.HelloRequest, global::Helloworld.HelloReply> __Method_SayHelloStream = new grpc::Method<global::Helloworld.HelloRequest, global::Helloworld.HelloReply>(
    grpc::MethodType.ClientStreaming,
    __ServiceName,
    "SayHelloStream",
    __Marshaller_helloworld_HelloRequest,
    __Marshaller_helloworld_HelloReply);

/// <summary>Creates service definition that can be registered with a server</summary>
/// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
public static grpc::ServerServiceDefinition BindService(GreeterBase serviceImpl)
{
  return grpc::ServerServiceDefinition.CreateBuilder()
      .AddMethod(__Method_SayHello, serviceImpl.SayHello)
      .AddMethod(__Method_SayHelloStream, serviceImpl.SayHelloStream).Build();
}

/// <summary>Register service method with a service binder with or without implementation. Useful when customizing the  service binding logic.
/// Note: this method is part of an experimental API that can change or be removed without any prior notice.</summary>
/// <param name="serviceBinder">Service methods will be bound by calling <c>AddMethod</c> on this object.</param>
/// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
public static void BindService(grpc::ServiceBinderBase serviceBinder, GreeterBase serviceImpl)
{
  serviceBinder.AddMethod(__Method_SayHello, serviceImpl == null ? null : new grpc::UnaryServerMethod<global::Helloworld.HelloRequest, global::Helloworld.HelloReply>(serviceImpl.SayHello));
  serviceBinder.AddMethod(__Method_SayHelloStream, serviceImpl == null ? null : new grpc::ClientStreamingServerMethod<global::Helloworld.HelloRequest, global::Helloworld.HelloReply>(serviceImpl.SayHelloStream));
}

}

(2).__Marshaller_helloworld_HelloRequest这个是实现protobuffer的序列化和反序列化的一个委托

服务的请求参数和返回参数,我们使用Protobuf-net来实现序列化和反序列化,和 WCF一样需要给类打上标签

/// <summary>
/// 加法请求参数
/// </summary>
[ProtoContract]
public class AddRequest
{
    /// <summary>
    /// 第一个数字
    /// </summary>
    [ProtoMember(1)]
    public int Num1 { get; set; }

    /// <summary>
    /// 第二个数字
    /// </summary>
    [ProtoMember(2)]
    public int Num2 { get; set; }
}

2.要实现CodeFirst需要实现这个BindService,把我们的Grpc方法添加到ServerServiceDefinition

(1).我们让Grpc服务实现IGrpcService空接口,用于标识是GrpcService

/// <summary>
/// MathGrpc
/// </summary>
public class MathGrpc : IGrpcService
{
    /// <summary>
    /// 加法
    /// </summary>
    /// <param name="request"></param>
    /// <param name="context"></param>
    /// <returns></returns>
    public Task<IntMessage> Add(AddRequest request, ServerCallContext context)
    {
        var result = new IntMessage();
        result.Value = request.Num1 + request.Num2;
        return Task.FromResult(result);
    }

}

(2).获取实现了IGrpcService接口的类,然后反射获取方法,再添加到ServerServiceDefinition即可

    /// <summary>
/// 注入IGrpcService
/// </summary>
/// <param name="grpcServices"></param>
/// <returns></returns>
private ServerBuilder UseGrpcService(IEnumerable<IGrpcService> grpcServices)
{
    var builder = ServerServiceDefinition.CreateBuilder();
    grpcServices.ToList().ForEach(grpc => GrpcMethodHelper.AutoRegisterMethod(grpc, builder));
    _serviceDefinitions.Add(builder.Build());
    return this;
}

未完,待续,欢迎评论拍砖

这些功能早在2018年就已经实现并运行在生产,感兴趣的同学可以去 github上查看,你要的都有,欢迎提issue

作  者: 易   磊(Rabbit_Yi)
出  处: http://www.cnblogs.com/rabbityi/

相关文章
|
2月前
|
网络协议 编译器 Go
玩转gRPC—深入概念与原理
玩转gRPC—深入概念与原理
44 0
|
6月前
|
负载均衡
gRPC源码分析(二):从官网文档看gRPC的特性
在第一部分,我们学习了gRPC的基本调用过程,这样我们对全局层面有了一定了解。接下来,我们将结合官方文档,继续深入学习、探索下去。
27 0
|
6月前
|
Java 编译器 API
gRPC 初探与简单使用
gRPC 初探与简单使用
31 0
|
运维 Dubbo 中间件
Dubbo3 源码解读-宋小生-6:Dubbo的SPI扩展机制之普通扩展对象的创建与Wrapper机制的源码解析
> Dubbo3 已经全面取代 HSF2 成为阿里的下一代服务框架,2022 双十一基于 Dubbo3 首次实现了关键业务不停推、不降级的全面用户体验提升,从技术上,大幅提高研发与运维效率的同时地址推送等关键资源利用率提升超 40%,基于三位一体的开源中间件体系打造了阿里在云上的单元化最佳实践和统一标准,同时将规模化实践经验与技术创新贡献开源社区,极大的推动了开源技术与标准的发展。 > 本文是
166 0
|
负载均衡 程序员 Go
Go RPC入门指南:RPC的使用边界在哪里?如何实现跨语言调用?
就是因为无法在同一个进程内,或者无法在同一个服务器上通过本地调用的方式实现我们的需求。 HTTP能满足需求但是不够高效,所以我们需要使用RPC。
145 0
Go RPC入门指南:RPC的使用边界在哪里?如何实现跨语言调用?
|
XML JSON 运维
【RPC基础系列2】一文搞懂gRPC和Thrift的基本原理和区别
之前对于gRPC和Thrift只停留在会用的阶段,虽然也初步了解过两者的执行流程,但时间一长又忘了,如果让我评估两者如何选型,我更是蒙圈。所以就想把之前学习的知识整理一下,来填补自己的知识盲区。
840 0
【RPC基础系列2】一文搞懂gRPC和Thrift的基本原理和区别
|
存储 缓存 负载均衡
为了带你搞懂RPC,我们手写了一个RPC框架
如今,分布式系统大行其道,RPC 有着举足轻重的地位。Dubbo、Thrift、gRpc 等框架各领风骚,学习RPC是新手也是老鸟的必修课。本文带你手撸一个rpc-spring-starter,深入学习和理解rpc相关技术,包括但不限于 RPC 原理、动态代理、Javassist 字节码增强、服务注册与发现、Netty 网络通讯、传输协议、序列化、包压缩、TCP 粘包、拆包、长连接复用、心跳检测、SpringBoot 自动装载、服务分组、接口版本、客户端连接池、负载均衡、异步调用等知识。
332 1
为了带你搞懂RPC,我们手写了一个RPC框架
|
XML NoSQL 中间件
手写RPC框架第三章《RPC中间件》
1、注册中心,生产者在启动的时候需要将本地接口发布到注册中心,我们这里采用redis作为注册中心,随机取数模拟权重。 2、客户端在启动的时候,连接到注册中心,也就是我们的redis。连接成功后将配置的生产者方法发布到注册中心{接口+别名}。 3、服务端配置生产者的信息后,在加载xml时候由中间件生成动态代理类,当发生发放调用时实际则调用了我们代理类的方法,代理里会通过netty的futuer通信方式进行数据交互。
431 0
|
XML NoSQL Dubbo
手写类似dubbo的rpc框架第三章《rpc框架》
本章将实现rpc的基础功能;提供一给rpc中间件jar给生产端和服务端。
113 0
手写类似dubbo的rpc框架第三章《rpc框架》
|
Java Android开发
Android插件化开发基础之Java动态代理(proxy)机制的简单例子
Android插件化开发基础之Java动态代理(proxy)机制的简单例子
226 0