grpc java 基础教程

article/2025/8/30 8:26:59

1 RPC 框架原理

RPC 框架的目标就是让远程服务调用更加简单、透明,RPC 框架负责屏蔽底层的传输方式(TCP 或者 UDP)、序列化方式(XML/Json/ 二进制)和通信细节。服务调用者可以像调用本地接口一样调用远程的服务提供者,而不需要关心底层通信细节和调用过程。


RPC 框架的调用原理图如下所示:



2 业界主流的 RPC 框架

业界主流的 RPC 框架整体上分为三类:
1. 支持多语言的 RPC 框架,比较成熟的有 Google 的 gRPC、Apache(Facebook)的 Thrift;
2. 只支持特定语言的 RPC 框架,例如新浪微博的 Motan;

3. 支持服务治理等服务化特性的分布式服务框架,其底层内核仍然是 RPC 框架, 例如阿里的 Dubbo。

随着微服务的发展,基于语言中立性原则构建微服务,逐渐成为一种主流模式,例如对于后端并发处理要求高的微服务,比较适合采用 Go 语言构建,而对于前端的 Web 界面,则更适合 Java 和 JavaScript。

因此,基于多语言的 RPC 框架来构建微服务,是一种比较好的技术选择。例如 Netflix,API 服务编排层和后端的微服务之间就采用 gRPC 进行通信。


3 gRPC 简介

gRPC 是一个高性能、开源和通用的 RPC 框架,面向服务端和移动端,基于 HTTP/2 设计。



4 gRPC 特点

1. 语言中立,支持多种语言;
2. 基于 IDL 文件定义服务,通过 proto3 工具生成指定语言的数据结构、服务端接口以及客户端 Stub;
3. 通信协议基于标准的 HTTP/2 设计,支持双向流、消息头压缩、单 TCP 的多路复用、服务端推送等特性,这些特性使得 gRPC 在移动端设备上更加省电和节省网络流量;

4. 序列化支持 PB(Protocol Buffer)和 JSON,PB 是一种语言无关的高性能序列化框架,基于 HTTP/2 + PB, 保障了 RPC 调用的高性能。


5 简单样例

本文的demo使用的项目构建工具是gradle,版本是4.6,配置如下:

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'com.google.protobuf'repositories {jcenter()
}buildscript {repositories {mavenCentral()}dependencies {classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.3'}
}sourceSets {main {java{srcDir 'gen/main/java'srcDir 'gen/main/grpc'}proto {srcDir 'src/main/proto'}}
}jar {from {configurations.runtime.collect {it.isDirectory() ? it : zipTree(it)}configurations.compile.collect {it.isDirectory() ? it : zipTree(it)}}manifest {attributes 'Main-Class': 'com.ylifegroup.protobuf.server.GRpcServer'}
}protobuf {protoc {artifact = "com.google.protobuf:protoc:3.5.1-1"}plugins {grpc {artifact = 'io.grpc:protoc-gen-grpc-java:1.11.0'}}generatedFilesBaseDir = "$projectDir/gen/"generateProtoTasks {all()*.plugins {grpc {}}}
}dependencies {//jsoncompile group: 'com.alibaba', name: 'fastjson', version: '1.2.8'//logbackcompile 'ch.qos.logback:logback-classic:1.1.8'//logstash-logback-encodercompile 'net.logstash.logback:logstash-logback-encoder:4.8'//grpccompile 'io.grpc:grpc-netty:1.11.0'compile 'io.grpc:grpc-protobuf:1.11.0'compile 'io.grpc:grpc-stub:1.11.0'//sslcompile 'io.netty:netty-tcnative-boringssl-static:2.0.8.Final'//nettycompile 'io.netty:netty-all:4.1.22.Final'// The production code uses the SLF4J logging API at compile timecompile 'org.slf4j:slf4j-api:1.7.21'testCompile 'junit:junit:4.12'
}tasks.withType(JavaCompile) {options.encoding = "UTF-8"options.fork = true
}eclipse {classpath {defaultOutputDir = file('build/eclipse/bin')}
}clean {delete protobuf.generatedFilesBaseDir
}

   简单说明一下,apply plugin: 'com.google.protobuf' ,这个是生成protobuf的强大工具,能够把proto文件生成protobuf对应的基础文件跟rpc文件;sourceSets定义了protobuf生成的规范,srcDir 'src/main/proto'表示存放proto原始文件目录, srcDir 'gen/main/java'表示存放proto基础文件的目录,srcDir 'gen/main/grpc'表示基础文件对应的rpc调用目录。整体项目结构图如下:


其中,grpc的基本依赖如下(no android):

//grpccompile 'io.grpc:grpc-netty:1.11.0'compile 'io.grpc:grpc-protobuf:1.11.0'compile 'io.grpc:grpc-stub:1.11.0'

按照之前概念说的,基于 IDL 文件定义服务,通过 proto3 工具生成指定语言的数据结构、服务端接口以及客户端 Stub,本demo 的 phonebook.proto 定义如下

syntax = "proto3";option go_package = "user";
option java_package = "com.ylifegroup.protobuf";enum PhoneType {HOME = 0;WORK = 1;OTHER = 2;
}message ProtobufUser {int32 id = 1;string name = 2;message Phone{PhoneType phoneType = 1;string phoneNumber = 2;}repeated Phone phones = 3;
}message AddPhoneToUserRequest{int32 uid = 1;PhoneType phoneType = 2;string phoneNumber = 3;
}message AddPhoneToUserResponse{bool result = 1;
}service PhoneService {rpc addPhoneToUser(AddPhoneToUserRequest) returns (AddPhoneToUserResponse);
}

其中rpc的配置是:

service PhoneService {rpc addPhoneToUser(AddPhoneToUserRequest) returns (AddPhoneToUserResponse);
}

其它部分都是基本数据的定义。

那么接下来怎么 通过 proto3 工具生成指定语言的数据结构、服务端接口以及客户端 Stub 呢?

运行gradle指令:  gradle build


我们看到生成了grpc对应的PhoneServiceGrpc文件,以及其基础类Phonebook。


到此基础工作已经准备好了,接下来我们构建server服务,构建server服务之前我们需要重新实现PhoneServiceGrpc,

/*** @describe PhoneService Imp* @author zhikai.chen* @date 2018年5月7日 下午3:56:54*/
import com.ylifegroup.protobuf.PhoneServiceGrpc;
import com.ylifegroup.protobuf.Phonebook.AddPhoneToUserRequest;
import com.ylifegroup.protobuf.Phonebook.AddPhoneToUserResponse;import io.grpc.stub.StreamObserver;public class PhoneServiceImp extends PhoneServiceGrpc.PhoneServiceImplBase{@Overridepublic void addPhoneToUser(AddPhoneToUserRequest request, StreamObserver<AddPhoneToUserResponse> responseObserver) {// TODO Auto-generated method stubAddPhoneToUserResponse response = null;if(request.getPhoneNumber().length() == 11 ){System.out.printf("uid = %s , phone type is %s, nubmer is %s\n", request.getUid(), request.getPhoneType(), request.getPhoneNumber());response = AddPhoneToUserResponse.newBuilder().setResult(true).build();}else{System.out.printf("The phone nubmer %s is wrong!\n",request.getPhoneNumber());response = AddPhoneToUserResponse.newBuilder().setResult(false).build();}responseObserver.onNext(response);responseObserver.onCompleted();}}

为了项目的简单易懂,这里我们使用默认的Block配置

import java.io.IOException;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import com.kenhome.protobuf.service.PhoneServiceImp;import io.grpc.Server;
import io.grpc.ServerBuilder;/*** @describe GRpcServer demo* @author zhikai.chen* @date 2018年5月7日 下午3:55:10*/
public class GRpcServerDefault {private static final Logger logger = LoggerFactory.getLogger(GRpcServerDefault.class);private Server server;private void start() throws IOException {/* The port on which the server should run */int port = 50051;server = ServerBuilder  .forPort(port).addService(new PhoneServiceImp()).build().start();logger.info("Server started, listening on " + port);Runtime.getRuntime().addShutdownHook(new Thread() {@Overridepublic void run() {System.err.println("*** shutting down gRPC server since JVM is shutting down");GRpcServerDefault.this.stop();System.err.println("*** server shut down");}});}private void stop() {if (server != null) {server.shutdown();}}/*** Await termination on the main thread since the grpc library uses daemon* threads.*/private void blockUntilShutdown() throws InterruptedException {if (server != null) {server.awaitTermination();}}/*** Main launches the server from the command line.*/public static void main(String[] args) throws IOException, InterruptedException {final GRpcServerDefault server = new GRpcServerDefault();server.start();server.blockUntilShutdown();}}

ServerBuilder  底层默认使用netty4.1的nio非阻塞模型。服务提供的内容通过addService添加 ,这里对应的是我们刚刚重写的PhoneServiceImp类。


最后我们来构建client类,一样的为了项目的易懂,这里也使用默认的Block配置:

import java.util.concurrent.TimeUnit;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import com.ylifegroup.protobuf.PhoneServiceGrpc;
import com.ylifegroup.protobuf.Phonebook.AddPhoneToUserRequest;
import com.ylifegroup.protobuf.Phonebook.AddPhoneToUserResponse;
import com.ylifegroup.protobuf.Phonebook.PhoneType;import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;/*** @describe GRpcClient Block demo* @author zhikai.chen* @date 2018年5月7日 下午4:00:58*/
public class GRpcClientBlock {private static final Logger logger = LoggerFactory.getLogger(GRpcClientBlock.class);private final ManagedChannel channel;private final PhoneServiceGrpc.PhoneServiceBlockingStub blockingStub;/** Construct client connecting to gRPC server at {@code host:port}. */public GRpcClientBlock(String host, int port) {ManagedChannelBuilder<?> channelBuilder = ManagedChannelBuilder.forAddress(host, port).usePlaintext();channel = channelBuilder.build();blockingStub = PhoneServiceGrpc.newBlockingStub(channel);}public void shutdown() throws InterruptedException {channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);}/** add phone to user. */public void addPhoneToUser(int uid, PhoneType phoneType, String phoneNubmer) {logger.info("Will try to add phone to user " + uid);AddPhoneToUserRequest request = AddPhoneToUserRequest.newBuilder().setUid(uid).setPhoneType(phoneType).setPhoneNumber(phoneNubmer).build();AddPhoneToUserResponse response;try {response = blockingStub.addPhoneToUser(request);} catch (StatusRuntimeException e) {logger.warn("RPC failed: {0} --> "+e.getLocalizedMessage(), e.getStatus());return;}logger.info("Result: " + response.getResult());}public static void main(String[] args) throws Exception {GRpcClientBlock client = new GRpcClientBlock("localhost", 50051);try {client.addPhoneToUser(1, PhoneType.WORK, "13888888888");} finally {client.shutdown();}}}
ManagedChannel 是对 Transport 层 SocketChannel 的抽象,Transport 层负责协议消息的序列化和反序列化,以及协议消息的发送和读取。

ManagedChannel 将处理后的请求和响应传递给与之相关联的 ClientCall 进行上层处理,同时,ManagedChannel 提供了对 Channel 的生命周期管理(链路创建、空闲、关闭等)。


运行效果:





好了,本教程就到这里了,下一章我会为大家讲解grpc有哪些io通信模型,以及他们各个部分简单的使用。



http://chatgpt.dhexx.cn/article/Vrb926SP.shtml

相关文章

【Java基础教程】Java学习路线攻略导图——史诗级别的细粒度归纳 ~

Java学习路线攻略导图 上篇 前言1、入门介绍篇2、程序基础概念篇3、包及访问权限篇4、异常处理篇5、特别篇6、面向对象篇7、新特性篇8、常用类库篇9、多线程篇10、IO篇11、网络编程篇12、集合体系篇13、JDBC篇 前言 &#x1f37a;&#x1f37a; 各位读者朋友大家好&#xff01…

idea java 单元测试_Java基础教程:IDEA单元测试

Java基础教程&#xff1a;IDEA单元测试 环境配置 使用idea IDE 进行单元测试&#xff0c;首先需要安装JUnit 插件。 安装JUnit插件步骤 File-->settings-->Plguins-->Browse repositories-->输入JUnit-->选择JUnit Generator V2.0安装。 安装完成后需要重新启动…

【Java基础教程】标识符与关键字

✅作者简介&#xff1a;大家好我是hacker707,大家可以叫我hacker &#x1f4c3;个人主页&#xff1a;hacker707的csdn博客 &#x1f525;系列专栏&#xff1a;Java基础教程 &#x1f4ac;推荐一款模拟面试、刷题神器&#x1f449;点击跳转进入网站 标识符与关键字 标识符关键字…

【Java基础教程】用Java实现猜数字小游戏

✅作者简介&#xff1a;大家好我是hacker707,大家可以叫我hacker &#x1f4c3;个人主页&#xff1a;hacker707的csdn博客 &#x1f525;系列专栏&#xff1a;Java基础教程 &#x1f4ac;推荐一款模拟面试、刷题神器&#x1f449;点击跳转进入网站 &#x1f3c6;在本周获得了新…

【Java基础教程】详解Java三种流程控制语句

✅作者简介&#xff1a;大家好我是hacker707,大家可以叫我hacker,新星计划第三季python赛道Top1&#x1f3c6; &#x1f4c3;个人主页&#xff1a;hacker707的csdn博客 &#x1f525;系列专栏&#xff1a;Java基础教程 &#x1f4ac;推荐一款模拟面试、刷题神器&#x1f449;点…

java基础教程:集合概述(27)

今天要讲的内容是集合。集合是我们编程时非常频繁的对象&#xff0c;必须花费大量时间学习。 我们还是从是什么和为什么两个角度进行引入。 集合是什么&#xff1f; 集合是存储和操作一组对象的对象。类似一个池子&#xff0c;可以存储操作一组元素。 为什么要有集合&#xf…

Java 零基础教程,看完就会,建议收藏

如果你不懂Java 并且想认真学习接触了解一下Java的语法&#xff0c;建议把这篇文章收藏了&#xff0c;多看几遍&#xff0c;应该可以初步掌握Java 大部分基础的语法 。 让我们出发吧&#xff01;ps:本文有点长&#xff0c;耐心阅读 。 〇&#xff0c;编程环境 工程项目推荐使…

找呀找呀找地铁

杭州地铁1号线据说2010年开通&#xff0c;还好下沙那边有地铁站&#xff0c;刚好在单位门口&#xff0c;不然在城区和这个鸟不生蛋的地方两头跑&#xff0c;可怎么活啊&#xff1f; 谁要以前不好好努力&#xff0c;多捞点钱呢&#xff1f;真是“老大徒伤悲”啊&#xff01;这个…

转载-高仙机器人落地北京杭州深圳多个城市地铁

你知道吗&#xff1f;世界上第一条地铁始建于1863年的伦敦&#xff0c;中国的地铁时代则在1969年的北京开启。 地铁作为黄金动脉&#xff0c;是衡量城市发展的关键指标之一。地铁不仅可以减少城市交通道路拥堵&#xff0c;带动周边地区发展&#xff0c;还可以减少环境污染&…

我国首个5G地铁站开通:TCL集团重组方案通过;苹果2019新品图泄露|雷锋早报...

我国首个5G地铁站在成都开通 近日&#xff0c;成都市政府新闻办发布消息称&#xff0c;全国首个5G地铁站&#xff08;地铁10号线太平园站&#xff09;已于1月5日在成都正式开通&#xff0c;该地铁站是全国第一个覆盖5G信号的地铁站&#xff0c;将成为四川移动对5G室内分布系统…

杭州治堵有“智慧” 阿里云数加激活城市大脑

城市车辆逐年增长&#xff0c;道路通行关系市民生活&#xff0c;也考验城市管理者智慧。除了加大基础设施投入&#xff0c;杭州对大数据的分析和应用成为治堵新发力点。在路网规划、精确治堵、科学调配资源等方面&#xff0c;都能看到“城市大脑”和大数据发挥的“智慧”作用。…

地铁一公里造价达7亿元,大部分城市无法回本,为何还抢着建?

最近几年我国各大城市兴起了一股地铁热&#xff0c;不管是大城市还是小城市&#xff0c;只要稍微符合条件的&#xff0c;很多城市都在纷纷规划建设地铁&#xff0c;目前包括已经有地铁在运营以及规划建设地铁的城市达到70个以上。 但是我们都知道&#xff0c;建地铁的成本是非常…

支付宝教会魔都地铁刷脸、扫码、懂人话

文/图 电商在线 朱婷 上午9点&#xff0c;小邵带着女朋友踏上了上海游玩的旅途。能顺利通过拥挤的地铁&#xff0c;是他们来到上海的第一个小愿望。 “我试一下宣传板上那个二维码。”看着高峰期买票的队伍&#xff0c;小邵不想让女朋友刚到&#xff0c;就在地铁口“罚站”。扫…

地铁与日本移动互联网

如果说中国的春运是每年全世界最大规模的人口迁徙&#xff0c;那么日本东京的上下班时间可能就是全球每天在发生的最大规模人口迁徙。 每天早上&#xff0c;日本人穿着整齐的西装&#xff0c;脚穿擦着发亮的皮鞋&#xff0c;提着公文包&#xff0c;整齐划一地挤上各种轨道交通工…

新华三:让地铁更智慧

当前&#xff0c;我国轨道交通正处于黄金发展期。国家发改委、交通运输部联合印发的《交通基础设施重大工程建设三年行动计划》指出&#xff1a;2016-2018年重点推进103个城市轨道交通项目前期工作&#xff0c;新建城市轨道交通2000公里以上&#xff0c;涉及投资约1.6万亿元。而…

云开发地铁路线图小程序源码和配置教程

☑️ 编号&#xff1a;ym415 ☑️ 品牌&#xff1a;无 ☑️ 语言&#xff1a;小程序 ☑️ 大小&#xff1a;580KB ☑️ 类型&#xff1a;地铁路线图 ☑️ 支持&#xff1a;小程序 &#x1f389; 欢迎关注(发消息才不限制)&#xff0c;私信&#xff0c;领取 &#x1f389; ✨ 源…

地铁规划

交通强国&#xff0c;铁路先行&#xff1b; 市域交通&#xff0c;得看地铁&#xff1b; 1.杭州篇 2.济南篇 3.上海篇 4.敬请期待1.杭州篇&#xff08;未完成&#xff09; “欲把西湖比西子&#xff0c;淡妆浓抹总相宜&#xff1b;” 杭州地铁一号线是浙江省第一条建成运营的地…

杭州城市交通拥堵综合治理实践

来源&#xff1a;世纪交通网 随着城镇化、机动化快速发展&#xff0c;杭州同国内许多城市一样&#xff0c;交通拥堵日益突出&#xff0c;已影响城市环境、运行效率及居民宜居感受。杭州自2013 年根据浙江省委省政府统一部署开始系统开展交通拥堵治理相关工作&#xff0c;经过多…

杭州地铁2号线西北段顺利通车 三思LED照明彰显“暖心”服务

近日&#xff0c;杭州地铁2号线一期西北段顺利开通&#xff0c;由上海三思提供的包括LED筒灯、LED面板灯、地铁区间隧道灯在内的两万余套照明设备和智能控制系统。 近日&#xff0c;杭州地铁2号线一期西北段顺利开通&#xff0c;起于庆春广场站&#xff0c;途经江干区、下城区…

艾宾浩斯记忆曲线

艾宾浩斯记忆曲线 艾宾浩斯实验结论艾宾浩斯实验算法注意 艾宾浩斯实验结论 知识进入大脑后只能形成短时记忆&#xff0c;短时记忆遗忘速度快&#xff1b;通过多次复习能把短时记忆转换为长时记忆&#xff0c;长时记忆遗忘效果慢。 艾宾浩斯实验算法 1.节省法&#xff1b; 2…