1.说明

本文介绍使用gRPC创建Java版本的RPC服务,
包括通过.proto文件生成Java代码的方法,
以及服务端和客户端代码使用示例。

2.创建生成代码工程

创建Maven工程,grpc-compile。

2.1.修改pom.xml

引入生成代码需要的jar包依赖,
以及构建依赖配置:

<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.32.1</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.32.1</version>
</dependency>
</dependencies>
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.6.2</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.12.0:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.32.1:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

2.2.创建.proto文件

在src\main下面新建proto目录,
在里面创建helloworld.proto文件:

// 显示声明使用proto3, 否则使用默认的proto2
syntax = "proto3"; // 生成类的包名
option java_package = "com.asiainfo.yuwen.grpc.helloworld";
// 生成类的文件名,否则默认生成的类名为proto文件名的驼峰命名
option java_outer_classname = "HelloWorldProto";
// 定义的所有消息、枚举和服务生成对应的多个类文件,而不是以内部类的形式出现
option java_multiple_files = false; // greeting服务定义
service Greeter {
// sayHello方法,格式为"方法名 请求参数 返回参数"
rpc SayHello (HelloRequest) returns (HelloReply) {}
// 另一个sayHello方法
rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}
} // 方法请求,包含用户名
message HelloRequest {
string name = 1;
} // 方法响应,包含响应的消息
message HelloReply {
string message = 1;
}

2.3.生成Java代码

在grpc-compile下执行Maven编译命令:

mvn clean compile

会在target目录下生成代码:

主要关注generated-sources目录:
generated-sources\protobuf\grpc-java目录下生成了
com\asiainfo\yuwen\grpc\helloworld\GreeterGrpc.java;
generated-sources\protobuf\java目录下生成了
com\asiainfo\yuwen\grpc\helloworld\HelloWorldProto.java。

其中GreeterGrpc.java对应greeting服务定义,
如果有多个服务,会对应生成多个java类,
HelloWorldProto.java对应消息、枚举等对象的定义。
由于生成的代码内容太多了,这里就不贴出来了。

3.创建服务端工程

创建Maven工程,grpc-server。

3.1.修改pom.xml

引入使用gRPC需要依赖的jar包:

<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.32.1</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.32.1</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.32.1</version>
</dependency>
</dependencies>

3.2.拷贝生成的代码

把上面生成的Java代码,
GreeterGrpc.java和HelloWorldProto.java,
拷贝到grpc-server的src/main/java目录下,
可以从com这一层目录开始拷贝,
这样就不用再手动创建包路径了。

3.3.创建greeting服务实现类

为了实现greeting服务定义的两个sayHello方法,
需要继承GreeterGrpc.GreeterImplBase接口,
创建实现类GreeterImpl.java:

package com.asiainfo.yuwen.grpc.helloworld.controller.impl;

import com.asiainfo.yuwen.grpc.helloworld.GreeterGrpc;
import com.asiainfo.yuwen.grpc.helloworld.HelloWorldProto.HelloReply;
import com.asiainfo.yuwen.grpc.helloworld.HelloWorldProto.HelloRequest; import io.grpc.stub.StreamObserver; /**
* <pre>
* greeting服务实现类
* </pre>
*/
public class GreeterImpl extends GreeterGrpc.GreeterImplBase { @Override
public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
} @Override
public void sayHelloAgain(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
HelloReply reply = HelloReply.newBuilder().setMessage("Hello again " + req.getName()).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}

3.4.创建服务端启动类

为了对外提供gRPC服务,
需要创建服务端启动类GRPCServer.java:

package com.asiainfo.yuwen.grpc.server;

import java.io.IOException;
import java.util.concurrent.TimeUnit; import com.asiainfo.yuwen.grpc.helloworld.controller.impl.GreeterImpl; import io.grpc.Server;
import io.grpc.ServerBuilder; /**
* gRPC服务启动类,启动时注册添加需要对外提供的服务类
*/
public class GRPCServer { private Server server; private void start() throws IOException {
// 服务运行端口
int port = 50051;
// 注册暴露对外提供的服务
server = ServerBuilder.forPort(port).addService(new GreeterImpl()).build().start();
System.out.println("Server started, listening on " + port); Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
// 使用标准错误输出,因为日志记录器有可能在JVM关闭时被重置
System.err.println("*** shutting down gRPC server since JVM is shutting down");
try {
GRPCServer.this.stop();
} catch (InterruptedException e) {
e.printStackTrace(System.err);
}
System.err.println("*** server shut down");
}
});
} private void stop() throws InterruptedException {
if (server != null) {
server.shutdown().awaitTermination(30, TimeUnit.SECONDS);
}
} /**
* 在主线程上等待终止,因为grpc库使用守护进程。
*/
private void blockUntilShutdown() throws InterruptedException {
if (server != null) {
server.awaitTermination();
}
} /**
* 启动服务Main方法
*/
public static void main(String[] args) throws IOException, InterruptedException {
final GRPCServer server = new GRPCServer();
server.start();
server.blockUntilShutdown();
}
}

3.5.服务端启动

通过执行GRPCServer的main方法,
就能启动服务了,
启动成功打印日志:

Server started, listening on 50051

4.创建服务端工程

创建Maven工程,grpc-client。

4.1.修改pom.xml

操作步骤和上面服务端相同。

4.2.拷贝生成的代码

操作步骤和上面服务端相同。
由于客户端和服务端都依赖了生成的代码,
以及依赖相同的jar包,
可以提取到common公共工程里面,
这样方便其他工程依赖和后续修改。

4.3.创建客户端调用类

创建一个简单的客户端,
用于测试greeting服务,
创建GRPCClient.java:

package com.asiainfo.yuwen.grpc.client;

import java.util.concurrent.TimeUnit;

import com.asiainfo.yuwen.grpc.helloworld.GreeterGrpc;
import com.asiainfo.yuwen.grpc.helloworld.HelloWorldProto.HelloReply;
import com.asiainfo.yuwen.grpc.helloworld.HelloWorldProto.HelloRequest; import io.grpc.Channel;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException; /**
* 一个简单的客户端,测试greeting服务
*/
public class GRPCClient { private final GreeterGrpc.GreeterBlockingStub greeterBlocStub; /**
* 构造使用现有通道访问服务端的客户端
*/
public GRPCClient(Channel channel) {
// 'channel'在这里是Channel,而不是ManagedChannel,所有它负责关闭 // 向代码传递通道可以使代码更容易测试,也可以更容易地重用通道。
// 同时这里创建的是同步(阻塞)RPC服务。
greeterBlocStub = GreeterGrpc.newBlockingStub(channel);
} /** 向服务端发送请求 */
public void greet(String name) {
System.out.println("Will try to greet " + name + " ...");
HelloRequest request = HelloRequest.newBuilder().setName(name).build();
HelloReply response;
try {
response = greeterBlocStub.sayHello(request);
} catch (StatusRuntimeException e) {
System.out.println("WARNING, RPC failed: Status=" + e.getStatus());
return;
}
System.out.println("Greeting: " + response.getMessage());
} /**
* 客户端启动入口,可以支持填写2个参数,否则使用默认值。 第1个参数是用户名。 第2个参数是目标服务器,格式IP:Port。
*/
public static void main(String[] args) throws Exception {
String user = "world";
// 访问本机在50051端口上运行的服务
String target = "localhost:50051";
// 命令行用法帮助,允许将用户名和目标服务器作为命令行参数传入。
if (args.length > 0) {
if ("--help".equals(args[0])) {
System.err.println("Usage: [name [target]]");
System.err.println("");
System.err.println(" name The name you wish to be greeted by. Defaults to " + user);
System.err.println(" target The server to connect to. Defaults to " + target);
System.exit(1);
}
user = args[0];
}
if (args.length > 1) {
target = args[1];
} // 创建到服务器的通信通道,通道是线程安全的和可重用的。
// 通常在应用程序开始时创建通道,并重用直到应用程序关闭。
ManagedChannel channel = ManagedChannelBuilder.forTarget(target).usePlaintext().build();
try {
GRPCClient client = new GRPCClient(channel);
client.greet(user);
} finally {
// ManagedChannels使用像线程和TCP连接这样的资源。
// 为了防止泄漏这些资源,通道应该在不再使用时关闭。
channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
}
}
}

4.4.客户端启动

通过执行GRPCClient的main方法,
就能启动客户端了,
通过gRPC调用服务端成功后打印日志:

Will try to greet world ...
Greeting: Hello world

5.参考文档

GRPC的JAVA使用介绍
Grpc系列一 第一个hello world 例子

gRPC创建Java RPC服务的更多相关文章

  1. 使用PHP来简单的创建一个RPC服务

    RPC全称为Remote Procedure Call,翻译过来为"远程过程调用".主要应用于不同的系统之间的远程通信和相互调用. 比如有两个系统,一个是PHP写的,一个是JAVA ...

  2. 从零开始基于go-thrift创建一个RPC服务

    Thrift 是一种被广泛使用的 rpc 框架,可以比较灵活的定义数据结构和函数输入输出参数,并且可以跨语言调用.为了保证服务接口的统一性和可维护性,我们需要在最开始就制定一系列规范并严格遵守,降低后 ...

  3. go-micro开发RPC服务的方法及其运行原理

    go-micro是一个知名的golang微服务框架,最新版本是v4,这篇文章将介绍go-micro v4开发RPC服务的方法及其运作原理. 基本概念 go-micro有几个重要的概念,后边开发RPC服 ...

  4. 应用AXIS开始Web服务之旅(soap web services)——使用三种不同的语言访问创建的Web服务,分别是JAVA、VB、VC

    一. 介绍 本文并不是想介绍Web服务的原理.系统架构等,我们假设您已经了解了关于Web服务的一些基本的概念.原理等知识.本文主要是针对那些已经了解Web服务概念,但是还没有亲身体会Web服务所带来令 ...

  5. <转>用 Java 技术创建 RESTful Web 服务

    转自:https://www.ibm.com/developerworks/cn/web/wa-jaxrs/#N1017E JAX-RS:一种更为简单.可移植性更好的替代方式 Dustin Amrhe ...

  6. 用 Java 技术创建 RESTful Web 服务

    JAX-RS:一种更为简单.可移植性更好的替代方式 JAX-RS (JSR-311) 是一种 Java™ API,可使 Java Restful 服务的开发变得迅速而轻松.这个 API 提供了一种基于 ...

  7. 2.Dubbo开源分布式服务框架(JAVA RPC)

    1. Dubbo介绍 Dubbox是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能RPC(即远程调用)实现服务的输出和输入功能, 可以和Spring框架无集成.Dubbo是一款高性能 ...

  8. 用 Java 技术创建 RESTful Web (服务 JAX-RS:一种更为简单、可移植性更好的替代方式)

    作者: Dustin Amrhein, 软件工程师, IBM Nick Gallardo, 软件工程师, IBM 出处: http://www.ibm.com/developerworks/cn/we ...

  9. JAVA RPC(一)RPC入门

    为什么要写这个RPC 市面上常见的RPC框架很多,grpc,motan,dubbo等,但是随着越来越多的元素加入,复杂的架构设计等因素似使得这些框架就想spring一样,虽然号称是轻量级,但是用起来却 ...

随机推荐

  1. [学习总结]9、Android-Universal-Image-Loader 图片异步加载类库的使用(超详细配置)

    这个图片异步加载并缓存的类已经被很多开发者所使用,是最常用的几个开源库之一,主流的应用,随便反编译几个火的项目,都可以见到它的身影. 可是有的人并不知道如何去使用这库如何进行配置,网上查到的信息对于刚 ...

  2. OC-私有方法,构造方法,类的本质及启动过程

    总结 标号 主题 内容 一 OC的私有方法 私有变量/私有方法 二 @property 概念/基本使用/寻找方法的过程/查找顺序 三 @synthesize @synthesize概念/基本使用/注意 ...

  3. 为什么要重写hashcode和equals方法

    我在面试 Java初级开发的时候,经常会问:你有没有重写过hashcode方法?不少候选人直接说没写过.我就想,或许真的没写过,于是就再通过一个问题确认:你在用HashMap的时候,键(Key)部分, ...

  4. Servlet+Jdbc+mysql实现登陆功能

    首先是新建一个servlet,servlet中有dopost和doget方法 一般的表格提交都是用post方法,故在dopost里面写入逻辑代码 下面是其逻辑代码Check.java protecte ...

  5. pandas读取csv文件中文乱码问题

    1.为什么会出现乱码问题,用什么方式编码就用什么方式解码,由于csv不是用的utf-8编码,故不能用它解码. 常用的编码方式有 utf-8,ISO-8859-1.GB18030等. 2.中文乱码原因: ...

  6. CPU测试工具

    目录 一.简介 二.大量计算 三.大量IO 四.大量进程 一.简介 使用stress-ng是一个 Linux 系统压力测试工具,模拟进程平均负载升高的场景. 使用sysstat来检查监控和分析. mp ...

  7. 前端浅谈---协议相关(TCP连接)

    TCP连接 http的描述里面,我弱化了交互过程的描述,因为它相对复杂.所以我在此单独描述.客户端和服务端传递数据时过程相对谨慎和复杂,主要是开始和结束的过程.而这整个过程就是TCP连接.连接流程大体 ...

  8. [BUUCTF]PWN8——jarvisoj_level0

    [BUUCTF]PWN8--jarvisoj_level0 题目网址:https://buuoj.cn/challenges#jarvisoj_level0 步骤: 例行检查,64位,开启了NX保护 ...

  9. ASP.NET VS 调试提示:指定的端口正在使用中,建议切换到xxx之外并大于1024的端口

    问题描述 使用 Visual Studio 开发 ASP.NET 网站的过程中,突然提示端口被占用: 解决方式 在启动项目上右键→属性,切换到 Web .直接修改服务器栏目里面的端口号,解决!

  10. CF761A Dasha and Stairs 题解

    Content 给定两个数 \(n,m\),试问是否有区间里面有 \(n\) 个奇数和 \(m\) 个偶数. 数据范围:\(0\leqslant n,m\leqslant 100\). Solutio ...