Search Tutorials


Spring Boot + gRPC Hello World Example | JavaInUse

Spring Boot + gRPC Hello World Example

In this tutorial we will be making use of Spring Boot to develop gRPC client and server code. In the next tutorial we will be creating the gRPC server using Spring Boot which will be consumed by gRPC client developed using C#.

gRPC - Table of Contents

Spring Boot+ gRPC Hello World Example Spring Boot gRPC Server + C# gRPC Client Example Spring Boot 3 + gRPC - Types of gRPC Spring Boot 3 + gRPC Unary Example Spring Boot 3 + gRPC Server Streaming Example Spring Boot 3 + gRPC Client Streaming Example Spring Boot 3 + gRPC Bidirectional Streaming Example Spring Boot + gRPC Deadline Example Spring Boot + gRPC Error Handling Example Spring Boot + gRPC Error Handling - Using Trailer Metadata Spring Boot + gRPC Error Handling - Global Exception Handler Using GrpcAdvice

Video

This tutorial is explained in the below Youtube Video.

What is gRPC

gRPC, short for Google Remote Procedure Call, is a high-performance open-source framework developed by Google. It facilitates communication between client and server applications, allowing them to call methods on each other as if they were making local function calls.

gRPC Hello World Example
Before we can understand the benefits of gRPC we need to understand the drawbacks of technologies used before gRPC.

Remote Procedure Call(RPC)

Remote Procedure Call (RPC) is a communication protocol used to enable inter-process communication between different systems. However, RPC has some disadvantages that limited its effectiveness. One major drawback is its tight coupling with specific programming languages and platforms. For example in Java applications makes use of Java RMI(Remote Method Invocation) for developing the required code skeletons and stubs. While .NET makes use of .NET Remoting for the same.
gRPC vs RPC
There is no RPC standard contract - Interface Definition Language (IDL), i.e. what functionality is to be implemented between the Client and Server.

Representational State Transfer (REST)

REST is another industry standard which is used widely. REST is language agnostic but has a limited set of primary 'function' calls
HTTP Verb CRUD
POST Create
GET Read
PUT Update/Replace
PATCH Update/Modify
DELETE Delete
This is not the case with gRPC. Using gRPC we can create any kind of function calls including synchronous/asynchronous, uni-direction/bidirectional(streams) etc.
The other major advantage of gRPC is that REST uses HTTP/1.1 while gRPC makes use of HTTP/2. HTTP/2 allows for lower latency (faster) connections that can take advantage of a single connection from client to server. HTTP/2 also supports bidirectional connectivity and asynchronous connectivity. So it is possible for the server to efficiently make contact with client to send messages

Advantages of gRPC

  • gRPC facilitates faster and more efficient communication between systems or services.
  • It allows for streamlined and quick exchange of data.
  • gRPC supports multiple programming languages, making it developer-friendly.
  • Built-in support for authentication and load balancing enhances security and scalability.
  • Efficient and secure communication through gRPC enhances performance and user experience in software projects.
  • gRPC utilizes Protocol Buffers, a language-agnostic binary serialization format, which enables efficient and compact communication over the network. This results in improved performance and reduced bandwidth consumption.

Implementation

We will be creating a gRPC Server that exposes an endpoint called GetBook. By utilizing the gRPC Client, we will consume this GetBook endpoint.
Spring Boot + gRPC Hello World Example

Spring Boot + gRPC Server Example

The maven project we will be creating is as follows -
Spring Boot + gRPC Server Example
Next we will be defining the proto file. A proto file in gRPC is a special type of file that helps define the structure and communication between different software components. It acts like a blueprint for creating and interacting with these components. In this specific example, the proto file contains information about a book request and response, along with a service called BookService that allows you to retrieve a book by sending a request and receiving a response.
syntax = "proto3";

import "constants/util.proto";

option java_multiple_files = true;
option java_package = "com.javainuse.employee";

message BookRequest{
  string book_id = 1;
}
message BookResponse {
  string book_id = 1;
  string name = 2;
  constants.Type type = 3;
}

service BookService {
  rpc getBook(BookRequest) returns (BookResponse) {};
}
The above proto file makes use of another proto file named util.proto where we define the enum Type.
syntax = "proto3";

package constants;

option java_multiple_files = true;
option java_package = "com.javainuse.constants";

enum Type {
  FANTASY = 0;
  AUTOBIOGRAPHY = 1;
  HISTORY = 2;
}
In pom.xml example we define the required gRPC dependencies. Also we make use of a maven plugin, called protobuf-maven-plugin. This is used to compile Protocol Buffers (protobuf) files in a Maven project. Protocol Buffers is a language-agnostic data serialization format. This plugin takes the protobuf files (defined in the specified <protoSourceRoot> directory) and generates Java code from them. This code enables communication between different components of the application, making it easier to exchange data in a structured and efficient manner.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.javainuse</groupId>
	<artifactId>Spring-Boot-GRPC-Server-Example</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.7</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<properties>
		<java.version>1.8</java.version>
		<protobuf.version>3.17.3</protobuf.version>
		<protobuf-plugin.version>0.6.1</protobuf-plugin.version>
		<grpc.version>1.42.1</grpc.version>
	</properties>
	
	<dependencies>

		<dependency>
			<groupId>net.devh</groupId>
			<artifactId>grpc-server-spring-boot-starter</artifactId>
			<version>2.9.0.RELEASE</version>
		</dependency>

		<dependency>
			<groupId>io.grpc</groupId>
			<artifactId>grpc-stub</artifactId>
			<version>${grpc.version}</version>
		</dependency>
		<dependency>
			<groupId>io.grpc</groupId>
			<artifactId>grpc-protobuf</artifactId>
			<version>${grpc.version}</version>
		</dependency>


		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.11.2</version>
		</dependency>

	</dependencies>

	<build>
		<extensions>
			<extension>
				<groupId>kr.motd.maven</groupId>
				<artifactId>os-maven-plugin</artifactId>
				<version>1.7.0</version>
			</extension>
		</extensions>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
			<plugin>
				<groupId>org.xolstice.maven.plugins</groupId>
				<artifactId>protobuf-maven-plugin</artifactId>
				<version>0.5.1</version>
				<configuration>
					<protocArtifact>
						com.google.protobuf:protoc:3.6.1:exe:
					</protocArtifact>
					<pluginId>grpc-java</pluginId>
					<pluginArtifact>
						io.grpc:protoc-gen-grpc-java:1.22.1:exe:
					</pluginArtifact>
					<protoSourceRoot>
						${basedir}/src/main/proto/
					</protoSourceRoot>
				</configuration>
				<executions>
					<execution>
						<goals>
							<goal>compile</goal>
							<goal>compile-custom</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>

</project>





In application.properties define the port on which the gRPC server will be running.
grpc.server.port=8090
Define the spring boot bootstrap class as follows -
package com.javainuse.book;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootGrpcServerExampleApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringBootGrpcServerExampleApplication.class, args);
	}

}
Next we will define a class named "BookService" that implements the functionality of a gRPC service for performing operations on books. The class is annotated with @GrpcService to indicate that it is a gRPC service. Also this class extends the BookServiceGrpc.BookServiceImplBase which is autogenerated class. Within the class, there is a method named getBook that takes a BookRequest object and a StreamObserver<BookResponse> object as parameters. This method is responsible for retrieving the details of a book based on the book ID. In the method, a mocked response is created using the BookResponse.newBuilder() method. This response includes fields like book ID, name, and type (autobiography). Finally, the response object is sent to the client using responseObserver.onNext(empResp), and the process is marked as completed with responseObserver.onCompleted().
package com.javainuse.book.service;

import com.javainuse.constants.Type;
import com.javainuse.employee.BookRequest;
import com.javainuse.employee.BookResponse;
import com.javainuse.employee.BookServiceGrpc;

import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;

@GrpcService
public class BookService extends BookServiceGrpc.BookServiceImplBase {

	/**
	 * Unary operation to get the book based on book id
	 * 
	 * @param request
	 * @param responseObserver
	 */
	@Override
	public void getBook(BookRequest request, StreamObserver<BookResponse> responseObserver) {

		// We have mocked the employee data.
		// In real world this should be fetched from database or from some other source
		BookResponse empResp = BookResponse.newBuilder().setBookId(request.getBookId()).setName("javainuse")
				.setType(Type.AUTOBIOGRAPHY).build();

		// set the response object
		responseObserver.onNext(empResp);

		// mark process is completed
		responseObserver.onCompleted();
	}
}
If we now start the spring boot project, the gRPC server gets started on port 9090.
Spring Boot + gRPC Server Start Up
We can test the Spring Boot + gRPC server using BloomRPC. Download the exe file and install it. Once installed we can give the proto file to load the service. In the request parameter we need to specify the book id and make call to get the response.
Spring Boot + gRPC BloomRPC

Spring Boot + gRPC Client Example

Create a maven project named spring-boot-grpc-client.
Spring Boot + gRPC Client Maven Project
This project will have the proto files similar to the one above.
syntax = "proto3";

import "constants/util.proto";

option java_multiple_files = true;
option java_package = "com.javainuse.employee";

message BookRequest{
  string book_id = 1;
}
message BookResponse {
  string book_id = 1;
  string name = 2;
  constants.Type type = 3;
}

service BookService {
  rpc getBook(BookRequest) returns (BookResponse) {};
}
The above proto file makes use of another proto file named util.proto where we define the enum Type.
syntax = "proto3";

package constants;

option java_multiple_files = true;
option java_package = "com.javainuse.constants";

enum Type {
  FANTASY = 0;
  AUTOBIOGRAPHY = 1;
  HISTORY = 2;
}
The pom.xml will be as follows.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.7</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.javainuse</groupId>
	<artifactId>Spring-Boot-GRPC-Client-Example</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<properties>
		<java.version>1.8</java.version>
		<protobuf.version>3.17.3</protobuf.version>
		<protobuf-plugin.version>0.6.1</protobuf-plugin.version>
		<grpc.version>1.42.1</grpc.version>
	</properties>
	<dependencies>

		<dependency>
			<groupId>net.devh</groupId>
			<artifactId>grpc-server-spring-boot-starter</artifactId>
			<version>2.9.0.RELEASE</version>
		</dependency>

		<dependency>
			<groupId>io.grpc</groupId>
			<artifactId>grpc-stub</artifactId>
			<version></version>
		</dependency>
		<dependency>
			<groupId>io.grpc</groupId>
			<artifactId>grpc-protobuf</artifactId>
			<version></version>
		</dependency>


		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.11.2</version>
		</dependency>

	</dependencies>

	<build>
		<extensions>
			<extension>
				<groupId>kr.motd.maven</groupId>
				<artifactId>os-maven-plugin</artifactId>
				<version>1.7.0</version>
			</extension>
		</extensions>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
			<plugin>
				<groupId>org.xolstice.maven.plugins</groupId>
				<artifactId>protobuf-maven-plugin</artifactId>
				<version>0.5.1</version>
				<configuration>
					<protocArtifact>
						com.google.protobuf:protoc:3.6.1:exe:
					</protocArtifact>
					<pluginId>grpc-java</pluginId>
					<pluginArtifact>
						io.grpc:protoc-gen-grpc-java:1.22.1:exe:
					</pluginArtifact>
					<protoSourceRoot>
						/src/main/proto/
					</protoSourceRoot>
				</configuration>
				<executions>
					<execution>
						<goals>
							<goal>compile</goal>
							<goal>compile-custom</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>

</project>
Next we will be creating class named BookService. It is used to access and interact with a remote BookService using the gRPC framework. It establishes a connection with the remote gRPC service using a network channel, sends a request for a book by providing its ID, and receives a response containing information about the book.
package com.javainuse.book.service;

import org.springframework.stereotype.Service;

import com.javainuse.employee.BookRequest;
import com.javainuse.employee.BookResponse;
import com.javainuse.employee.BookServiceGrpc;

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

@Service
public class BookService {

	public void getBook() {

		ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 8090).usePlaintext().build();

		BookServiceGrpc.BookServiceBlockingStub stub = BookServiceGrpc.newBlockingStub(channel);

		BookResponse bookResponse = stub.getBook(BookRequest.newBuilder().setBookId("1").build());

		System.out.println(bookResponse);

		channel.shutdown();
	}
}
Next we will be defining the spring boot bootstrap class. In this class we get an instance of the BookService we defined above and call the getBook method.
package com.javainuse.book;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

import com.javainuse.book.service.BookService;

@SpringBootApplication
public class SpringBootGrpcClientExampleApplication {

	public static void main(String[] args) {
		ApplicationContext context = SpringApplication.run(SpringBootGrpcClientExampleApplication.class, args);
		BookService bookService = context.getBean(BookService.class);
		bookService.getBook();

	}

}
If we now start the project using above class, the gRPC clients calls and consumes the getBook endpoint exposed by the gRPC server.
Spring Boot + gRPC Client output

Download Source Code

Download it - Spring Boot + GRPC Client Example
Download it - Spring Boot + GRPC Server Example