gRPC的Java实现

Posted 早起的码农

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了gRPC的Java实现相关的知识,希望对你有一定的参考价值。

     

  • 基本概念

       gRPC 一开始由 google 开发,是一款语言中立、平台中立、开源的远程过程调用(RPC)系统。在 gRPC 里,客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法,使得您能够更容易地创建分布式应用和服务。与许多 RPC 系统类似,gRPC 也是基于以下理念:定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个 gRPC 服务器来处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法。


gRPC具有以下特点:

(1)基于 HTTP/2, 继而提供了连接多路复用、Body 和 Header 压缩等机制。可以节省带宽、降低TCP链接次数、节省CPU使用和延长电池寿命等。

(2)支持主流开发语言(C, C++, Python, php, Ruby, NodeJS, C#, Objective-C、Golang、Java)

(3)IDL (Interface Definition Language) 层使用了 Protocol Buffers, 非常适合团队的接口设计

  • HelloWorld实例详解

gRPC的使用通常包括如下几个步骤:

  1. 通过protobuf来定义接口和数据类型

  2. 编写gRPC server端代码

  3. 编写gRPC client端代码

  • 编写helloworld.proto

syntax = "proto3";
option
java_multiple_files = true;
option
java_package = "com.manong.helloworld";
option
java_outer_classname = "HelloWorldProto";
option
objc_class_prefix = "HLW";
package
helloworld;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
string name = 1;
}

// The response message containing the greetings
message HelloReply {
string message = 1;
}


  • Maven配置


<properties>
<protobuf.version>
3.12.0</protobuf.version>
<protoc.version>
3.12.0</protoc.version>
<grpc.version>
1.31.1</grpc.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>
io.grpc</groupId>
<artifactId>
grpc-bom</artifactId>
<version>
1.31.1</version>
<type>
pom</type>
<scope>
import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>
io.grpc</groupId>
<artifactId>
grpc-protobuf</artifactId>
</dependency>
<dependency>
<groupId>
io.grpc</groupId>
<artifactId>
grpc-stub</artifactId>
</dependency>
<dependency>
<groupId>
io.grpc</groupId>
<artifactId>
grpc-services</artifactId>
</dependency>
<dependency>
<groupId>
io.grpc</groupId>
<artifactId>
grpc-netty-shaded</artifactId>
<scope>
runtime</scope>
</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:${protoc.version}:exe:${os.detected.classifier}</protocArtifact>
<pluginId>
grpc-java</pluginId>
<pluginArtifact>
io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>
compile</goal>
<goal>
compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>
org.apache.maven.plugins</groupId>
<artifactId>
maven-enforcer-plugin</artifactId>
<version>
1.4.1</version>
<executions>
<execution>
<id>
enforce</id>
<goals>
<goal>
enforce</goal>
</goals>
<configuration>
<rules>
<requireUpperBoundDeps/>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>


运行maven插件中下面命令,根据proto生成源代码

gRPC的Java实现


项目target下生成如下代码,实际项目上线后可以把该代码copy到对应src下面,把target下面的源码删除掉,这样也不用每次用maven中plugin去再生成代码。


gRPC的Java实现


  • Server端代码


import com.manong.grpc.helloworld.GreeterGrpc;
import
com.manong.grpc.helloworld.HelloReply;
import
com.manong.grpc.helloworld.HelloRequest;
import
io.grpc.Server;
import
io.grpc.ServerBuilder;
import
io.grpc.stub.StreamObserver;
import
java.io.IOException;
import
java.net.InetAddress;
import
java.util.Random;
import
java.util.concurrent.TimeUnit;
import
java.util.logging.Level;
import
java.util.logging.Logger;
public class
HostnameServer extends GreeterGrpc.GreeterImplBase {
private static final Logger logger = Logger.getLogger(HostnameServer.class.getName());
private final
String serverName;
public
HostnameServer(String serverName) {
if (serverName == null) {
serverName = determineHostname();
}
this.serverName = serverName;
}

@Override
public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
HelloReply reply = HelloReply.newBuilder()
.setMessage("Hello , " + req.getName() + ", from " + serverName)
.build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}

private static String determineHostname() {
try {
return InetAddress.getLocalHost().getHostName();
} catch (IOException ex) {
logger.log(Level.INFO, "Failed to determine hostname. Will generate one", ex);
}
// Strange. Well, let's make an identifier for ourselves.
return "generated-" + new Random().nextInt();
}


public void init() throws Exception {
int port = 50051;
String hostname = "0.0.0.0";
final
Server server = ServerBuilder.forPort(port)
.addService(this)
.build()
.start();
System.out.println("Listening on port " + port);
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
server.shutdown();
try
{
if (!server.awaitTermination(30, TimeUnit.SECONDS)) {
server.shutdownNow();
server.awaitTermination(5, TimeUnit.SECONDS);
}
} catch (InterruptedException ex) {
server.shutdownNow();
}
}
});
server.awaitTermination();
}

public static void main(String[] args) throws Exception {
HostnameServer hostnameServer = new HostnameServer("grpc server");
hostnameServer.init();
}
}


运行Server,出现如下输出表示Server已经正常启动



  • Client端代码


import com.manong.grpc.helloworld.GreeterGrpc;
import
com.manong.grpc.helloworld.HelloReply;
import
com.manong.grpc.helloworld.HelloRequest;
import
io.grpc.ManagedChannel;
import
io.grpc.ManagedChannelBuilder;
public class
HostnameClient {

public static void main(String[] args) {
String target = "localhost:50051";
ManagedChannel channel = ManagedChannelBuilder.forTarget(target).usePlaintext().build();
try
{
GreeterGrpc.GreeterBlockingStub greeterBlockingStub = GreeterGrpc.newBlockingStub(channel);
//传参
HelloRequest defaultInstance = HelloRequest.newBuilder().setName("manong").build();
HelloReply helloReply = greeterBlockingStub.sayHello(defaultInstance);
System.out.println(helloReply.getMessage());
} catch (Exception e) {
e.printStackTrace();
}

}
}


运行client端代码,出现如下输出,表示调用server服务成功并获得返回值

到此为止,一个完整的基于Java的gRpc demo就完成了。想了解更多可以猛击https://grpc.io/

以上是关于gRPC的Java实现的主要内容,如果未能解决你的问题,请参考以下文章

java版gRPC实战之二:服务发布和调用

案例篇:利用ProtoBuf文件,一键生成Java代码

gRPC的Java实现

gRPC Java 服务端实现简析

Java 开发 gRPC 服务和客户端

GRPC框架源码分析