news 2026/4/16 15:55:23

Java gRPC 调用完全指南:从 IDL 定义到微服务实战,含单元测试与拦截器详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java gRPC 调用完全指南:从 IDL 定义到微服务实战,含单元测试与拦截器详解

🚀 前言:为什么是 gRPC?

在微服务架构中,RESTful API 虽然通用,但在内部服务调用场景下,它的效率成为了瓶颈(JSON 序列化慢、HTTP/1.1 头部冗余)。
gRPC基于HTTP/2Protobuf,提供了二进制传输、多路复用、双向流等特性,性能比 REST 高出一个数量级。

本文将带你从 0 构建一个包含普通调用流式调用的订单服务,并手写拦截器单元测试


🛠️ 第一阶段:环境搭建与 IDL 定义

gRPC 的核心是Contract First(契约优先)。我们需要先写.proto文件。

1. Maven 依赖与插件

这是最容易劝退新手的环节。你需要配置protobuf-maven-plugin来自动生成 Java 代码。

<dependencies><dependency><groupId>io.grpc</groupId><artifactId>grpc-netty-shaded</artifactId><version>1.54.0</version></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-protobuf</artifactId><version>1.54.0</version></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-stub</artifactId><version>1.54.0</version></dependency><dependency><groupId>org.apache.tomcat</groupId><artifactId>annotations-api</artifactId><version>6.0.53</version><scope>provided</scope></dependency></dependencies><build><extensions><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>1.7.1</version></extension></extensions><plugins><plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.6.1</version><configuration><protocArtifact>com.google.protobuf:protoc:3.21.7:exe:${os.detected.classifier}</protocArtifact><pluginId>grpc-java</pluginId><pluginArtifact>io.grpc:protoc-gen-grpc-java:1.54.0:exe:${os.detected.classifier}</pluginArtifact></configuration><executions><execution><goals><goal>compile</goal><goal>compile-custom</goal></goals></execution></executions></plugin></plugins></build>
2. 定义order.proto

我们在src/main/proto下创建文件。为了演示深度,我们定义两个接口:一个简单调用,一个服务端流式调用(Server Streaming)。

syntax = "proto3"; package com.example.grpc; option java_multiple_files = true; option java_package = "com.example.grpc.lib"; option java_outer_classname = "OrderProto"; service OrderService { // 1. 简单一元调用:根据 ID 查订单 rpc GetOrder (OrderRequest) returns (OrderResponse); // 2. 服务端流式调用:实时获取订单状态流 rpc WatchOrderStatus (OrderRequest) returns (stream OrderStatus); } message OrderRequest { int32 order_id = 1; } message OrderResponse { int32 order_id = 1; string product_name = 2; double price = 3; } message OrderStatus { string status = 1; string timestamp = 2; }

执行mvn compile,你会发现在target/generated-sources下生成了 Java 代码。


💻 第二阶段:服务端实现 (Server)

服务端需要继承生成的ImplBase类。

publicclassOrderServiceImplextendsOrderServiceGrpc.OrderServiceImplBase{// 1. 实现简单调用@OverridepublicvoidgetOrder(OrderRequestrequest,StreamObserver<OrderResponse>responseObserver){System.out.println("收到查询请求 ID: "+request.getOrderId());// 模拟数据库查询OrderResponseresponse=OrderResponse.newBuilder().setOrderId(request.getOrderId()).setProductName("MacBook Pro M3").setPrice(12999.00).build();// 返回数据responseObserver.onNext(response);// 结束调用 (必须调用,否则客户端会一直等待)responseObserver.onCompleted();}// 2. 实现服务端流式调用 (Server Streaming)@OverridepublicvoidwatchOrderStatus(OrderRequestrequest,StreamObserver<OrderStatus>responseObserver){// 模拟订单状态变化:每隔1秒推送一次String[]statuses={"已下单","支付成功","仓库配货","已发货","派送中"};for(Stringstatus:statuses){try{Thread.sleep(500);}catch(InterruptedExceptione){}OrderStatusorderStatus=OrderStatus.newBuilder().setStatus(status).setTimestamp(System.currentTimeMillis()+"").build();// 推送一条流数据responseObserver.onNext(orderStatus);}responseObserver.onCompleted();}}

启动 Server:

publicclassGrpcServer{publicstaticvoidmain(String[]args)throwsIOException,InterruptedException{// 添加拦截器 (后面讲)Serverserver=ServerBuilder.forPort(9090).addService(ServerInterceptors.intercept(newOrderServiceImpl(),newAuthInterceptor())).build();server.start();System.out.println("gRPC Server started on port 9090");server.awaitTermination();}}

🔌 第三阶段:客户端调用 (Client)

客户端通常使用Stub (存根)来调用。

publicclassGrpcClient{publicstaticvoidmain(String[]args){// 1. 创建通道 (Connection)ManagedChannelchannel=ManagedChannelBuilder.forAddress("localhost",9090).usePlaintext()// 测试环境使用明文传输.build();// 2. 创建 Stub// BlockingStub: 同步阻塞调用OrderServiceGrpc.OrderServiceBlockingStubblockingStub=OrderServiceGrpc.newBlockingStub(channel);// 3. 简单调用OrderResponseresponse=blockingStub.getOrder(OrderRequest.newBuilder().setOrderId(1001).build());System.out.println("查询结果: "+response.getProductName());// 4. 流式调用 (需要用 Iterator)Iterator<OrderStatus>statusIterator=blockingStub.watchOrderStatus(OrderRequest.newBuilder().setOrderId(1001).build());while(statusIterator.hasNext()){OrderStatusstatus=statusIterator.next();System.out.println("当前状态: "+status.getStatus());}channel.shutdown();}}

🛡️ 第四阶段:进阶 —— 拦截器 (Interceptor)

在生产环境中,我们不可能裸奔。我们需要拦截器来做Auth 鉴权日志记录
gRPC 使用Metadata(类似 HTTP Header) 来传递元数据。

服务端拦截器:验证 Token

publicclassAuthInterceptorimplementsServerInterceptor{privatestaticfinalMetadata.Key<String>TOKEN_KEY=Metadata.Key.of("auth-token",Metadata.ASCII_STRING_MARSHALLER);@Overridepublic<ReqT,RespT>ServerCall.Listener<ReqT>interceptCall(ServerCall<ReqT,RespT>call,Metadataheaders,ServerCallHandler<ReqT,RespT>next){// 获取客户端传来的 TokenStringtoken=headers.get(TOKEN_KEY);if("secret-123".equals(token)){// 验证通过,放行returnnext.startCall(call,headers);}else{// 验证失败,直接关闭连接call.close(Status.UNAUTHENTICATED.withDescription("Token无效"),headers);returnnewServerCall.Listener<>(){};}}}

客户端发送 Token:

// 客户端需要自定义一个 CallCredentials 或者使用 ClientInterceptor// 这里使用 MetadataUtils 快速注入OrderServiceGrpc.OrderServiceBlockingStubstub=OrderServiceGrpc.newBlockingStub(channel);Metadatameta=newMetadata();meta.put(Metadata.Key.of("auth-token",Metadata.ASCII_STRING_MARSHALLER),"secret-123");// 将 Metadata 附着在 Stub 上stub=MetadataUtils.attachHeaders(stub,meta);

🧪 第五阶段:单元测试 (Test)

这是区分新手和高手的地方。
不要启动真实的 Server 去测,太慢且依赖网络。
gRPC 提供了grpc-testing库,支持InProcessServer (进程内服务器),速度极快。

引入依赖:

<dependency><groupId>io.grpc</groupId><artifactId>grpc-testing</artifactId><version>1.54.0</version><scope>test</scope></dependency>

编写 JUnit 5 测试用例:

publicclassOrderServiceTest{privateServerinProcessServer;privateManagedChannelinProcessChannel;privateOrderServiceGrpc.OrderServiceBlockingStubblockingStub;@BeforeEachpublicvoidsetUp()throwsException{// 生成唯一的服务器名称StringserverName=InProcessServerBuilder.generateName();// 1. 启动进程内服务器 (绑定我们实现的 Service)inProcessServer=InProcessServerBuilder.forName(serverName).directExecutor()// 不使用线程池,直接在当前线程执行,方便测试.addService(newOrderServiceImpl()).build().start();// 2. 创建连接到该服务器的 ChannelinProcessChannel=InProcessChannelBuilder.forName(serverName).directExecutor().build();blockingStub=OrderServiceGrpc.newBlockingStub(inProcessChannel);}@AfterEachpublicvoidtearDown(){inProcessChannel.shutdown();inProcessServer.shutdown();}@TestpublicvoidtestGetOrder(){// givenOrderRequestrequest=OrderRequest.newBuilder().setOrderId(888).build();// whenOrderResponseresponse=blockingStub.getOrder(request);// thenassertEquals(888,response.getOrderId());assertEquals("MacBook Pro M3",response.getProductName());}}

📝 总结

通过这篇文章,你掌握了 gRPC 开发的完整闭环:

  1. IDL 定义proto文件是核心契约。
  2. 流式通信:用StreamObserver实现实时推送。
  3. 拦截器:用Metadata实现 Token 鉴权。
  4. InProcess 测试:不依赖网络的极速单元测试。

gRPC 不仅仅是高性能,更是规范化微服务调用的利器。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/31 20:00:09

GHOST误操作致分区消失?一招教你找回丢失数据

在数据备份与恢复的领域里&#xff0c;GHOST作为一款曾经广泛使用的系统备份与还原工具&#xff0c;为众多用户带来了便利。然而&#xff0c;不当的操作或误选选项&#xff0c;有时会导致意想不到的后果——比如&#xff0c;原本多分区存储的数据&#xff0c;在GHOST操作后&…

作者头像 李华
网站建设 2026/4/16 12:23:44

前端剪贴板功能实现方案:从零到一的完整技术指南

前端剪贴板功能实现方案&#xff1a;从零到一的完整技术指南 【免费下载链接】clipboard.js :scissors: Modern copy to clipboard. No Flash. Just 3kb gzipped :clipboard: 项目地址: https://gitcode.com/gh_mirrors/cl/clipboard.js 前端剪贴板功能在现代Web应用中扮…

作者头像 李华
网站建设 2026/4/16 12:59:36

亲测!专业机油批发的实践与成果

亲测&#xff01;专业机油批发的实践与成果引言在汽车后市场中&#xff0c;机油批发业务具有广阔的发展前景。四川小江军作为一家专注于机油领域的品牌&#xff0c;在专业机油批发方面有着丰富的实践经验和显著的成果。本文将结合亲测体验&#xff0c;探讨专业机油批发的实践要…

作者头像 李华
网站建设 2026/4/16 12:27:05

如何用字节跳动开源AI助手让工作效率翻倍?

如何用字节跳动开源AI助手让工作效率翻倍&#xff1f; 【免费下载链接】UI-TARS-2B-SFT 项目地址: https://ai.gitcode.com/hf_mirrors/ByteDance-Seed/UI-TARS-2B-SFT 还在为重复的电脑操作烦恼吗&#xff1f;每天花费大量时间在Excel数据处理、邮件整理、文件归档上&…

作者头像 李华
网站建设 2026/4/11 22:35:17

智慧园区系统:技术赋能下的园区管理革新与价值升级

在数字经济加速渗透的今天&#xff0c;智慧园区系统已成为破解传统园区管理瓶颈、激活产业发展动能的核心支撑。它不再是简单的技术叠加&#xff0c;而是集数据整合、智能管控、服务优化于一体的综合性管理生态&#xff0c;通过融合大数据、物联网、云计算、人工智能等前沿技术…

作者头像 李华
网站建设 2026/4/16 14:32:09

OptiLayer V2025.11光学薄膜设计软件

1. 运算与生产适配性强&#xff1a;采用独特针式算法&#xff0c;运算速度比同类软件快数百倍&#xff0c;即便处理数十层复杂膜层&#xff0c;也能在不中断沉积过程的前提下完成参数测定与优化&#xff0c;还能降低生产成本、缩短生产周期。同时算法对生产和监测误差的稳定性大…

作者头像 李华