Search Tutorials


Spring Boot 3 + gRPC Unary Example | JavaInUse

Spring Boot 3 + gRPC Unary Example

In previous tutorial we looked at Different types of gRPC calls. In this tutorial we will be implementing spring boot + gRPC unary call. Unary gRPC is a type of communication protocol that allows client-server interactions where the client sends a single request to the server and gets a single response back. This means that the client sends one piece of data to the server and waits for a response.
For example, if you want to fetch a single item from a database, authenticate a user, or perform a calculation and obtain the result, unary gRPC can be a good choice.
We will be implementing the following scenario.

Scenario

Consider a banking service where the the client needs to get the account balance. For this a unary gRPC call is made to the server which returns the balances.
Bank Unary gRPC

Video

This tutorial is explained in the below Youtube Video.

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

Implementation

Spring Boot Unary gRPC Server

We will be creating a maven project as follows -
Spring Boot 3 + gRPC Unary Example
The pom.xml will be as follows. We have the following dependencies
  • spring-boot-starter-parent- We have used version - 3.2.0. It provides default configurations, dependencies, and plugins that are commonly used in Spring Boot applications.
  • grpc-server-spring-boot-starter- We have used version - 2.15.0. Which is the latest dependency provided by maven repository. It provides the necessary components to integrate and run a gRPC server within a Spring Boot application.
  • grpc-stub-- We have used version - 1.59.0. This dependency provides classes and utilities for creating and using gRPC stubs, which are used to make remote procedure calls.
  • grpc-protobuf-- We have used version - 1.59.0. This library provides support for the Protocol Buffers serialization format used in gRPC, allowing you to define and exchange structured data between your gRPC client and server.
  • annotations-api- We have used version - 6.0.53. This artifact provides the necessary annotations for Java code generated by the protobuf-maven-plugin.
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 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.
<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>boot-unary-grpc-server</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.2.0</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<protobuf.version>3.17.3</protobuf.version>
		<protobuf-plugin.version>0.6.1</protobuf-plugin.version>
		<grpc.version>1.59.0</grpc.version>
	</properties>
	<dependencies>

		<dependency>
			<groupId>net.devh</groupId>
			<artifactId>grpc-server-spring-boot-starter</artifactId>
			<version>2.15.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>org.apache.tomcat</groupId>
			<artifactId>annotations-api</artifactId>
			<version>6.0.53</version>
			<scope>provided</scope>
		</dependency>

	</dependencies>

	<build>
		<extensions>
			<extension>
				<groupId>kr.motd.maven</groupId>
				<artifactId>os-maven-plugin</artifactId>
				<version>1.7.1</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.6.1</version>
				<configuration>
					<protocArtifact>
						com.google.protobuf:protoc:3.24.0:exe:${os.detected.classifier}
					</protocArtifact>
					<pluginId>grpc-java</pluginId>
					<pluginArtifact>
						io.grpc:protoc-gen-grpc-java:1.59.0:exe:${os.detected.classifier}
					</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>
Next create the proto file named bank-service.proto in src/main/proto folder.
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. The bank-service.proto file is used to define the structure and behavior of messages in a banking program. It includes two message types: AccountRequest and AccountBalanceResponse. AccountRequest is used to request a client's account balance, and AccountBalanceResponse is used to send a server's response with the account number and balance. The file also includes a service called AccountBalanceService, which has a method called GetAccountBalance for retrieving account balances.
syntax = "proto3";

package banking;

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

// Message representing a client's account balance request
message AccountRequest {
  string account_number = 1;
}

// Message representing a server's response to a client's account balance request
message AccountBalanceResponse {
  string account_number = 1;
  double balance = 2;
}

// Service for retrieving account balance
service AccountBalanceService {
  rpc GetAccountBalance (AccountRequest) returns (AccountBalanceResponse) {}
}




Next create the spring bootstrap class as follows-
package com.javainuse.bank;

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);
	}
}
Run the maven install command which will generate the classes using the proto file.
Next create the service named BankAccountBalanceService. We use the @GrpcService to expose this class as a grpc service. The BankAccountBalanceService class is a gRPC service that extends AccountBalanceServiceGrpc.AccountBalanceServiceImplBase. AccountBalanceServiceGrpc.AccountBalanceServiceImplBase is the abstract base class generated by the gRPC framework based on the protocol buffer definition file bank-service.proto for the service. By extending the generated base class, you get a template with the necessary methods and can focus on implementing the business logic without worrying about handling low-level details of the gRPC communication. It has a method called getAccountBalance that takes an AccountRequest and a StreamObserver as parameters. It creates a new AccountBalanceResponse object with a hardcoded balance of 100 and sends it as a response using the StreamObserver. Even though it is a unary call (which means it only receives a single response), the use of StreamObserver allows for unified handling and flexibility in gRPC. Finally, it marks the process as completed.
package com.javainuse.bank.service;

import com.javainuse.banking.AccountBalanceResponse;
import com.javainuse.banking.AccountBalanceServiceGrpc;
import com.javainuse.banking.AccountRequest;

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

@GrpcService
public class BankAccountBalanceService extends AccountBalanceServiceGrpc.AccountBalanceServiceImplBase {

	@Override
	public void getAccountBalance(AccountRequest request,
			StreamObserver<com.javainuse.banking.AccountBalanceResponse> responseObserver) {

		AccountBalanceResponse empResp = AccountBalanceResponse.newBuilder()
				.setAccountNumber(request.getAccountNumber()).setBalance(100).build();

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

		// mark process is completed
		responseObserver.onCompleted();
	}
}
Next create a file named application.properties where we specify the grpc port configuration-
grpc.server.port=8090

Test using BloomRPC

Start the spring boot project created. Start BloomRPC and load the proto file. This will create the gRPC client.
Spring Boot 3 + gRPC Unary BloomRPC

Spring Boot Unary gRPC Client

We will be creating a maven project as follows -
Spring Boot 3 + gRPC Unary Client
The pom.xml will be as follows-
<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>boot-unary-grpc-client</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.2.0</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<protobuf.version>3.17.3</protobuf.version>
		<protobuf-plugin.version>0.6.1</protobuf-plugin.version>
		<grpc.version>1.59.0</grpc.version>
	</properties>
	<dependencies>

		<dependency>
			<groupId>net.devh</groupId>
			<artifactId>grpc-server-spring-boot-starter</artifactId>
			<version>2.15.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>org.apache.tomcat</groupId>
			<artifactId>annotations-api</artifactId>
			<version>6.0.53</version>
			<scope>provided</scope>
		</dependency>

	</dependencies>

	<build>
		<extensions>
			<extension>
				<groupId>kr.motd.maven</groupId>
				<artifactId>os-maven-plugin</artifactId>
				<version>1.7.1</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.6.1</version>
				<configuration>
					<protocArtifact>
						com.google.protobuf:protoc:3.24.0:exe:${os.detected.classifier}
					</protocArtifact>
					<pluginId>grpc-java</pluginId>
					<pluginArtifact>
						io.grpc:protoc-gen-grpc-java:1.59.0:exe:${os.detected.classifier}
					</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>
Next create the proto file named bank-service.proto in src/main/proto folder
syntax = "proto3";

package banking;

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

// Message representing a client's account balance request
message AccountRequest {
  string account_number = 1;
}

// Message representing a server's response to a client's account balance request
message AccountBalanceResponse {
  string account_number = 1;
  double balance = 2;
}

// Service for retrieving account balance
service AccountBalanceService {
  rpc GetAccountBalance (AccountRequest) returns (AccountBalanceResponse) {}
}
Next create the spring bootstrap class as follows-
package com.javainuse.bank;

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

@SpringBootApplication
public class SpringBootGrpcClientExampleApplication {

	public static void main(String[] args) throws InterruptedException {
		SpringApplication.run(SpringBootGrpcClientExampleApplication.class, args);
	}
}
Run the maven install command which will generate the classes using the proto file. Next create the service class. The BankService class is a service that fetches the account balance from a remote server using gRPC communication. It creates a channel to connect to the server, retrieves the account balance, and prints the response. Finally, it shuts down the channel.
package com.javainuse.bank.service;

import org.springframework.stereotype.Service;

import com.javainuse.banking.AccountBalanceResponse;
import com.javainuse.banking.AccountBalanceServiceGrpc;
import com.javainuse.banking.AccountRequest;

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

@Service
public class BankService {

	public void getAccountBalance() {

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

		AccountBalanceServiceGrpc.AccountBalanceServiceBlockingStub stub = AccountBalanceServiceGrpc
				.newBlockingStub(channel);

		AccountBalanceResponse bookResponse = stub
				.getAccountBalance(AccountRequest.newBuilder().setAccountNumber("account5").build());

		System.out.println(bookResponse);

		channel.shutdown();

	}
}
Finally modify the bootstrap SpringBootGrpcClientExampleApplication class to call the getAccountBalance method of the BankService-
package com.javainuse.bank;

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

import com.javainuse.bank.service.BankService;

@SpringBootApplication
public class SpringBootGrpcClientExampleApplication {

	public static void main(String[] args) throws InterruptedException {
		ApplicationContext context = SpringApplication.run(SpringBootGrpcClientExampleApplication.class, args);
		BankService bankService = context.getBean(BankService.class);
		bankService.getAccountBalance();
	}
}
Run the client to get the response.
Spring Boot 3 + gRPC Unary Client Output


	

Download Source Code

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