What is gRPC? A Brief Introduction with JAVA

Yunus Kılıç
Analytics Vidhya
Published in
6 min readJan 22, 2020

--

“gRPC is a modern open source high performance RPC framework that can run in any environment. It can efficiently connect services in and across data centers with pluggable support for load balancing, tracing, health checking and authentication. It is also applicable in last mile of distributed computing to connect devices, mobile applications and browsers to backend services.”[1]

Cloud Native Computing Foundation is the new home for gRPC and its existing ecosystem projects (https://github.com/grpc and https://github.com/grpc-ecosystem)

There are some comparisons with Rest, SOAP etc. In this tutorial I will not make a comparison. But you can find some of them 1,2,3.

Outline of the tutorial:

1-) Define a service in a .proto file using Protocol Buffers IDL

2-) Generate server

3-) Client stub code using the protocol buffer compiler.

1-)Defining a service with proto file

By default, gRPC uses protocol buffers, Google’s mature open source mechanism for serializing structured data.

“Protocol buffers are a flexible, efficient, automated mechanism for serializing structured data — think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages. You can even update your data structure without breaking deployed programs that are compiled against the “old” format.”[2]

!Important!: There is a basic tutorial for Java at the gRPC site[5]. But documentation is not fully covered the whole process, especially you are a newbie. There are some assumptions that you are very familiar with the concept. I will mention extra steps to understand concepts and how to solve problems.

Sample proto file with version 3.[4]

syntax = "proto3";package tutorial;import "google/protobuf/timestamp.proto";

option java_multiple_files = true;
option java_package = "com.example.tutorial";
option java_outer_classname = "AddressGuideProtos";
service AddressGuide {
rpc GetAddressBook(Person) returns (AddressBook) {}
}
message Person {
string name = 1;
int32 id = 2; // Unique ID number for this person.
string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
repeated PhoneNumber phones = 4;
google.protobuf.Timestamp last_updated = 5;
}
// Our address book file is just one of these.
message AddressBook {
repeated Person people = 1;
}

This proto file will be used to generate sources by the compiler. Before going on to the compiler phase, let’s describe some options.

option java_multiple_files = true;

Create objects inside different files.

option java_package = "com.example.tutorial";

Setting Java package name.

  • Downloading Protocol Buffer and Setup Compiler

Download the latest file. You can download programming language-specific file or all which contains whole supported language. I used all version.

Supported languages: C++,Java, Go, C#, Python, Objective-C, JavaScript, Ruby, Php, Dart

Unix Installation(Windows installation inside Github repo readme):

./configure
make
make check
sudo make install
sudo ldconfig

You can find sample command to generate resources at Github repo.

protoc --java_out=${OUTPUT_DIR} path/to/your/proto/file

Java documentation which I cited earlier, has an expression below.

“The following classes are generated from our service definition:

Feature.java, Point.java, Rectangle.java, and others which contain all the protocol buffer code to populate, serialize, and retrieve our request and response message types.

RouteGuideGrpc.java which contains (along with some other useful code):

a base class for RouteGuide servers to implement, RouteGuideGrpc.RouteGuideImplBase, with all the methods defined in the RouteGuide service.

stub classes that clients can use to talk to a RouteGuide server.”

!!!The documentation uses a different example: RouteGuide. And says that RouteGuideGrpc should be generated. The above command will not generate RouteGuideGrpc for any case. Also, AddressGuideGrpc will not be generated.But the official document says servers should implement generated base class(RouteGuideImplBase) which is located inside the Grpc file. With respect to your proto file, there should be a base class with all method definitions. There is not any information about how this file generated at the documentation. You could be stuck at this step easily. After some research result is:

  • You need to use protoc plugin to generate this important file.

Repo of the plugin which describes where and how to download:

So my final command to generate all sources below:

protoc -plugin=protoc-gen-grpc-java=/PATH/protoc-gen-grpc-java-1.26.0-osx-x86_64.exe SOURCE_DIST -java_out=DEST_DIR -I=DEST_DIR    -grpc-java_out=DEST_DIR

-plugin=protoc-gen-grpc-java

to generate XXImplBase class.

PS: You need to give access to the executable plugin on macos.

https://stackoverflow.com/questions/55023435/grpc-out-protoc-gen-grpc-plugin-failed-with-status-code-1-on-osx-java

Sources were generated. Model classes and AddressGuideGrpc.java are both ready. The next step is creating a maven project. Copy sources to the project. And add below dependencies.

<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.11.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.26.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.26.0</version>
</dependency>

Github link for full code:

2-) gRPC Server

package com.example.tutorial;

import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

public class GrpcServer {
private static final Logger logger = Logger.getLogger(GrpcServer.class.getName());

private final int port;
private final Server server;

public GrpcServer(int port) {
this(ServerBuilder.forPort(port), port);
}

public GrpcServer(ServerBuilder<?> serverBuilder, int port) {
this.port = port;
ArrayList<AddressBook> addressBooks = new ArrayList();
server = serverBuilder.addService(new AddressGuideService(addressBooks))
.build();
}

public static void main(String[] args) throws IOException, InterruptedException {
GrpcServer server = new GrpcServer(8980);
server.start();
server.blockUntilShutdown();
}

private void blockUntilShutdown() throws InterruptedException {
if (server != null) {
server.awaitTermination();
}
}

private void start() throws IOException {
server.start();
logger.info("Server started, listening on " + port);
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
// Use stderr here since the logger may have been reset by its JVM shutdown hook.
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);
}
}

private static class AddressGuideService extends AddressGuideGrpc.AddressGuideImplBase {
private final Collection<AddressBook> addressbookCollection;

public AddressGuideService(Collection<AddressBook> addressBookCollection) {
this.addressbookCollection = addressBookCollection;
}

@Override
public void getAddressBook(Person request, StreamObserver<AddressBook> responseObserver) {
responseObserver.onNext(getAddressBook());
responseObserver.onCompleted();
}

private AddressBook getAddressBook() {
return AddressBook.newBuilder().addPeople(Person.newBuilder().build()).build();
}
}
}

AddressGuideService extends AddressGuideGrpc.AddressGuideImplBase

as I cited earlier, we need to extend ImplBase class which was generated from our proto. We need to override services. In our case, I returned an empty object basically.

Start, stop and blockUntilShutdown parts are the same with gRPC documentation. Our server will listen to 8980 port.

3-) gRPC Client

package com.example.tutorial;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;

import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

public class GrpcClient {

private static final Logger logger = Logger.getLogger(GrpcClient.class.getName());

private final ManagedChannel channel;
private final AddressGuideGrpc.AddressGuideBlockingStub blockingStub;
private final AddressGuideGrpc.AddressGuideStub asyncStub;

public GrpcClient(String host, int port) {
this(ManagedChannelBuilder.forAddress(host, port).usePlaintext());
}

public GrpcClient(ManagedChannelBuilder<?> channelBuilder) {
channel = channelBuilder.build();
blockingStub = AddressGuideGrpc.newBlockingStub(channel);
asyncStub = AddressGuideGrpc.newStub(channel);
}

public static void main(String[] args) throws InterruptedException {
GrpcClient grpcClient = null;
try{
grpcClient = new GrpcClient("127.0.0.1", 8980);
AddressBook addressBook = grpcClient.getAddressBook(Person.newBuilder().build());;
}catch (Exception e){

}finally {
grpcClient.shutdown();
}
}

public void shutdown() throws InterruptedException {
channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
}

public AddressBook getAddressBook(Person person) {
return blockingStub.getAddressBook(person);
}
}

After starting gRPC server, run the client and see the expected result.

PS: After shutdown await termination is suggested.

All done

Thanks :)

Cites:

1-) https://grpc.io/

2-) https://developers.google.com/protocol-buffers/docs/overview

3-) https://cloud.google.com/apis/design/proto3

4-) https://github.com/protocolbuffers/protobuf/blob/master/examples/addressbook.proto

5-) https://grpc.io/docs/tutorials/basic/java/

--

--

Yunus Kılıç
Analytics Vidhya

I have 10 years of experience in high-quality software application development, implementation, and integration.