| 创建时间: | 2019/11/16 19:37 |
|---|---|
| 作者: | sunpengwei1992@aliyun.com |
都说grpc是跨语言的一个rpc框架,当团队内部有多种流行编程语言时,那么grpc可以为他们提供通信,今天我们就通过一个Hello World来看看Java和Go是怎么通信的,一起实践吧,只有亲身实践才能更好的掌握,理解。
下文所有程序源代码地址如下
Java:https://github.com/sunpengwei1992/java_grpc
Go:https://github.com/sunpengwei1992/go_common/tree/master/grpc
我们以Go作为服务端,Java作为客户端
Go实现服务端
准备好Go版的proto文件
syntax = "proto3";package proto;//接口请求入参message HelloRequest{string request = 1;}//接口返回出参message HelloResponse{string response = 1;}//定义接口service HelloService{//一个简单的rpcrpc HelloWorld(HelloRequest) returns (HelloResponse){}//一个服务器端流式rpcrpc HelloWorldServerStream(HelloRequest) returns (stream HelloResponse){}//一个客户端流式rpcrpc HelloWorldClientStream(stream HelloRequest) returns (HelloResponse){}//一个客户端和服务器端双向流式rpcrpc HelloWorldClientAndServerStream(stream HelloRequest)returns (stream HelloResponse){}}
下载依赖的moudle,如下地址
github.com/golang/protobuf v1.3.2google.golang.org/grpc v1.23.1
执行如下命令,生成proto.pb.go文件
protoc --goout=plugins=grpc:. helloworld.proto
服务端实现接口,提供服务
type HelloServiceServer struct {}func (*HelloServiceServer) HelloWorld(ctx context.Context,req *pb.HelloRequest) (*pb.HelloResponse, error) {//打印入参log.Printf("%v", req.Request)//响应服务return &pb.HelloResponse{Response: "hello my is gRpcServer"}, nil}
编写服务端代码,并启动服务端
func StartServer() {lis, err := net.Listen("tcp", "127.0.0.1:8090")if err != nil {log.Fatalf("failed to listen: %v", err)}//创建一个grpc服务器对象gRpcServer := grpc.NewServer()pb.RegisterHelloServiceServer(gRpcServer, &impl.HelloServiceServer{})//开启服务端gRpcServer.Serve(lis)}
到次为止,Go服务端启动完成,接下来我们准备Java客户端代码
Java实现客户端
准备好Java版的proto文件,和Go版的区别是多了一些Java的选项,其余的不能改变
syntax = "proto3";package proto; //包名和go中的必须一致option java_generic_services = true;option java_multiple_files = true;option java_package = "com.spw.proto";option java_outer_classname = "HelloWorldProto";//接口请求入参message HelloRequest{string request = 1;}//接口返回出参message HelloResponse{string response = 1;}//定义接口service HelloService{//一个简单的rpcrpc HelloWorld(HelloRequest) returns (HelloResponse){}//一个服务器端流式rpcrpc HelloWorldServerStream(HelloRequest) returns (stream HelloResponse){}//一个客户端流式rpcrpc HelloWorldClientStream(stream HelloRequest) returns (HelloResponse){}//一个客户端和服务器端双向流式rpcrpc HelloWorldClientAndServerStream(stream HelloRequest) returns (stream HelloResponse){}}
新建一个maven项目,配置pom文件,依赖的jar包如下
<dependencies><dependency><groupId>io.grpc</groupId><artifactId>grpc-protobuf</artifactId><version>1.23.1</version></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-stub</artifactId><version>1.23.1</version></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-netty-shaded</artifactId><version>1.23.1</version></dependency></dependencies>
编译配置如下
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.5.1</version><configuration><!--proto编译器 os.detected.classifier,获取操作系统,这个属性是由${os.detected.name}-${os.detected.arch}一起得来的--><protocArtifact>com.google.protobuf:protoc:3.7.1:exe:${os.detected.classifier}</protocArtifact><pluginId>grpc-java</pluginId><!--grpc-java代码生成工具--><pluginArtifact>io.grpc:protoc-gen-grpc-java:1.23.1:exe:${os.detected.classifier}</pluginArtifact></configuration><executions><execution><goals><goal>compile</goal><goal>compile-custom</goal></goals></execution></executions></plugin></plugins><!--用于根据.proto 文件生成 protobuf 文件--><extensions><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>1.5.0.Final</version></extension></extensions></build>
开始根据proto文件编译生成java文件,如下图所示,依次点击红色的插件
编写客户端文件,连接Go的服务端,发起请求
//通过netty创建通道ManagedChannel channel = NettyChannelBuilder.forAddress("127.0.0.1", 8090).negotiationType(NegotiationType.PLAINTEXT).build();//获取客户端存根对象HelloServiceGrpc.HelloServiceBlockingStub blockingStub = HelloServiceGrpc.newBlockingStub(channel);//创建入参HelloRequest helloRequest = HelloRequest.newBuilder().setRequestBytes(ByteString.copyFromUtf8("hello grpc")).build();//调用服务端HelloResponse helloResponse = blockingStub.helloWorld(helloRequest);//打印响应System.out.println(helloResponse.getResponse());
我们以Java作为服务端,Go作为客户端
Java实现服务端
上面Java客户端生成的文件不要懂,另写一个服务的实现类,代码如下
public class HelloServiceImpl extends HelloServiceGrpc.HelloServiceImplBase {/*** <pre>*一个简单的rpc* </pre>*/@Overridepublic void helloWorld(HelloRequest request,io.grpc.stub.StreamObserver<HelloResponse>responseObserver) {responseObserver.onNext(HelloResponse.newBuilder().setResponse("hello my is java server").build());responseObserver.onCompleted();}}
写一个main方法启动服务端,代码如下
public static void main(String[] args) {try {CountDownLatch countDownLatch = new CountDownLatch(1);//启动服务端Server server = ServerBuilder.forPort(8090)//添加自己的服务实现类.addService(new HelloServiceImpl()).build().start();countDownLatch.await();} catch (IOException e) {} catch (InterruptedException e) {}}
Go作为客户端
上面go服务端生成的proto文件依然不要变,实现自己的客户端代码,如下
func StartClient() {conn, err := grpc.Dial("127.0.0.1:8090", grpc.WithInsecure())if err != nil {fmt.Println(err)return}//创建客户端存根对象c := pb.NewHelloServiceClient(conn)//调用服务res, err := c.HelloWorld(context.Background(),new(pb.HelloRequest), grpc.EmptyCallOption{})fmt.Println(res, err)defer conn.Close()}
总结
通过一个HelloWorld的案例带领大家实践多语言通过grpc通信,真实场景中,往往非常复杂,还需要大家多多研究,比如,负载均衡,限流,服务降级,protobuffer文件管理,版本升级等各种问题都需要考虑,grpc的专栏也就到这里了,希望大家通过这十篇文章能有有所收获,更加深入的需要大家在实践中自己摸索,思考,总结。想深入交流的可以留言获取我的邮箱地址。
欢迎大家关注微信公众号:“golang那点事”,更多精彩期待你的到来
