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.
Create the model class named Transaction. This will be the response we will be sending as stream data.
package com.javainuse.bank.model;
public class Transaction {
private String id;
private String type;
private float amount;
public Transaction() {
}
public Transaction(String id, String type, float amount) {
super();
this.id = id;
this.type = type;
this.amount = amount;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public float getAmount() {
return amount;
}
public void setAmount(float amount) {
this.amount = amount;
}
}
Create the service named TransactionHistoryService.
We use the @GrpcService to expose this class as a grpc service and expose it over the gRPC protocol.
The TransactionHistoryService class is a gRPC service that extends TransactionServiceGrpc.TransactionServiceImplBase.
TransactionServiceGrpc.TransactionServiceImplBase 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 fetches transaction details based on a duration and sends them in batches.
The
fetchTransactions
fetches mock transaction data and
createTransactionDetailFromTransaction method creates a transaction detail creates from this
mock transaction data. The class handles sending batches with a delay.
package com.javainuse.bank.service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.javainuse.bank.model.Transaction;
import com.javainuse.banking.AccountRequest;
import com.javainuse.banking.TransactionDetail;
import com.javainuse.banking.TransactionDetailList;
import com.javainuse.banking.TransactionServiceGrpc;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;
@GrpcService
public class TransactionHistoryService extends TransactionServiceGrpc.TransactionServiceImplBase {
@Override
public void streamTransactions(AccountRequest request, StreamObserver<TransactionDetailList> responseObserver) {
// Assuming you have a method to fetch transaction details based on the duration
// in days
List<Transaction> transactions = fetchTransactions(request.getDurationInDays());
int batchSize = 3; // How many transactions to send at once
for (int i = 0; i < transactions.size(); i += batchSize) {
int endIndex = Math.min(i + batchSize, transactions.size());
List<Transaction> batchTransactions = transactions.subList(i, endIndex);
TransactionDetailList.Builder transactionDetailListBuilder = TransactionDetailList.newBuilder();
for (Transaction transaction : batchTransactions) {
TransactionDetail transactionDetail = createTransactionDetailFromTransaction(transaction);
transactionDetailListBuilder.addTransactionDetails(transactionDetail);
}
TransactionDetailList transactionDetailList = transactionDetailListBuilder.build();
responseObserver.onNext(transactionDetailList);
// Delay between sending batches (if necessary)
// You can adjust this based on your requirements
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
responseObserver.onError(e);
return;
}
}
responseObserver.onCompleted();
}
private TransactionDetail createTransactionDetailFromTransaction(Transaction transaction) {
return TransactionDetail.newBuilder().setTransactionId(transaction.getId())
.setTransactionType(transaction.getType()).setTransactionAmount(transaction.getAmount()).build();
}
private List<Transaction> fetchTransactions(int durationInDays) {
List<Transaction> transactions = new ArrayList<>();
// Mock data for transaction details
Transaction transaction1 = new Transaction("1", "Deposit", 100.0f);
Transaction transaction2 = new Transaction("2", "Withdrawal", 50.0f);
Transaction transaction3 = new Transaction("3", "Transfer", 75.0f);
Transaction transaction4 = new Transaction("4", "Deposit", 200.0f);
Transaction transaction5 = new Transaction("5", "Withdrawal", 30.0f);
transactions.addAll(Arrays.asList(transaction1, transaction2, transaction3, transaction4, transaction5));
return transactions;
}
}
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 Server Streaming gRPC Client
We will be creating a maven project as follows -

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-server-streaming-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 transaction request
message AccountRequest {
string account_number = 1;
int32 duration_in_days = 2;
}
// Message representing a transaction detail
message TransactionDetail {
string transaction_id = 1;
string transaction_type = 2;
float transaction_amount = 3;
}
message TransactionDetailList {
repeated TransactionDetail transaction_details = 1;
}
// Service for streaming transaction details
service TransactionService {
// Method to stream transaction details for a given duration in days
rpc streamTransactions(AccountRequest) returns (stream TransactionDetailList);
}
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.
The TransactionServiceClient class creates a client to communicate with a transaction service.
It establishes a connection with the service using a host and port or an existing channel.
It can stream transactions for a specified account number and duration. It also provides a method to shut down the connection.
package com.javainuse.bank.service;
import java.util.concurrent.TimeUnit;
import com.javainuse.banking.AccountRequest;
import com.javainuse.banking.TransactionDetailList;
import com.javainuse.banking.TransactionServiceGrpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.stub.StreamObserver;
public class TransactionServiceClient {
private final ManagedChannel channel;
private final TransactionServiceGrpc.TransactionServiceStub asyncStub;
public TransactionServiceClient(String host, int port) {
this(ManagedChannelBuilder.forAddress(host, port).usePlaintext().build());
}
public TransactionServiceClient(ManagedChannel channel) {
this.channel = channel;
asyncStub = TransactionServiceGrpc.newStub(channel);
}
public void streamTransactions(String accountNumber, int durationInDays) {
AccountRequest request = AccountRequest.newBuilder().setAccountNumber(accountNumber)
.setDurationInDays(durationInDays).build();
asyncStub.streamTransactions(request, new StreamObserver<TransactionDetailList>() {
@Override
public void onNext(TransactionDetailList transactionDetail) {
// Handle each incoming TransactionDetail here
System.out.println("Received transaction detail: " + transactionDetail);
}
@Override
public void onError(Throwable throwable) {
System.err.println("Error occurred during transaction streaming: " + throwable);
}
@Override
public void onCompleted() {
System.out.println("Transaction streaming completed");
}
});
}
public void shutdown() throws InterruptedException {
channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
}
}
BankService class is marked as a service. It has a method getTransactions() which connects to
a TransactionServiceClient at localhost:8090. It streams transactions for account "123456789"
for 30 seconds. It waits indefinitely to receive all transactions unless a timeout is added. Finally, it shuts down the client.
package com.javainuse.bank.service;
import java.util.concurrent.CountDownLatch;
import org.springframework.stereotype.Service;
@Service
public class BankService {
public void getTransactions() throws InterruptedException {
TransactionServiceClient client = new TransactionServiceClient("localhost", 8090);
client.streamTransactions("123456789", 30);
// Wait indefinitely to receive all transactions. Add a timeout if required.
new CountDownLatch(1).await();
client.shutdown();
}
}
Finally modify the spring bootstrap class to call the getTransactions 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.getTransactions();
}
}
Run the client to get the response.
Download Source Code
Download it -
Spring Boot + gRPC Server Streaming Client Example
Download it -
Spring Boot + gRPC Server Streaming Server Example