Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
945 changes: 473 additions & 472 deletions pom.xml

Large diffs are not rendered by default.

126 changes: 126 additions & 0 deletions remote-procedure-invocation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
---
title: "Remote Procedure Invocation (RPI) Pattern in Java: Synchronous Communication Between Microservices"
shortTitle: Remote Procedure Invocation
description: "Learn the Remote Procedure Invocation (RPI) pattern in Java for enabling synchronous request/reply communication between microservices using REST and Spring Boot."
category: Integration
language: en
tag:
- Client-server
- Decoupling
- Integration
- Microservices
- Synchronous
---
## Also Known As

* Remote Procedure Call (RPC)

## Intent of Remote Procedure Invocation Pattern

Enable synchronous communication between microservices using a request/reply protocol such as REST, where a client makes a direct call to a remote service and blocks until the response is received.

## Detailed Explanation of Remote Procedure Invocation Pattern with Real-World Examples

Real-world example

> Consider an e-commerce application where the checkout service needs to verify a customer's shipping address by calling the address-validation service. The checkout service sends an HTTP request with the address details and waits for the validation result before proceeding. This synchronous request/reply interaction is the essence of RPI — direct, blocking communication between two services without an intermediate message broker.

In plain words

> Remote Procedure Invocation lets one microservice call another over the network using a request/reply protocol (typically HTTP/REST) as if calling a local method, while both must be available at the time of the call.

## Programmatic Example of Remote Procedure Invocation Pattern in Java

This example demonstrates a simple RPI setup using Spring Boot. The `RpiService` exposes a REST endpoint, and the `RpiClient` uses `RestTemplate` to call it synchronously.

**The Service (Server Side)**

The `RpiService` is a Spring `@RestController` that exposes a `/greet` endpoint:

```java
@RestController
public class RpiService {

@GetMapping("/greet")
public String greet(@RequestParam(defaultValue = "World") String name) {
return "Hello, " + name + "!";
}
}
```
**The Client**

The `RpiClient` uses `RestTemplate` to make a synchronous HTTP GET request to the service:
```java
@Slf4j
public class RpiClient {

private final RestTemplate restTemplate;
private final String baseUrl;

public RpiClient(RestTemplate restTemplate, String baseUrl) {
this.restTemplate = restTemplate;
this.baseUrl = baseUrl;
}

public String greet(String name) {
var url = baseUrl + "/greet?name=" + name;
LOGGER.info("Calling remote service: {}", url);
var response = restTemplate.getForObject(url, String.class);
LOGGER.info("Received response: {}", response);
return response;
}
}
```
**Running the example**

Start the application and then make a call:

```bash
curl http://localhost:8080/greet?name=Java
```
**Console Output**
```bash
Hello, Java!
```
## When to Use the Remote Procedure Invocation Pattern in Java

* When services need synchronous request/reply communication.
* When simplicity is preferred over asynchronous messaging infrastructure.
* When the client needs an immediate response from the service before proceeding.

## Remote Procedure Invocation Pattern Class Diagram

![Remote Procedure Invocation](./etc/rpi.urm.png)

## Real-World Applications of Remote Procedure Invocation Pattern in Java

* RESTful API calls between microservices using `RestTemplate` or `WebClient`.
* gRPC-based service-to-service communication.
* Any HTTP-based synchronous inter-service call in a microservice architecture.

## Benefits and Trade-offs of Remote Procedure Invocation Pattern

Benefits:

* Simple and familiar programming model — similar to calling a local method.
* No need for intermediate message broker infrastructure.
* Easy to understand, debug, and trace.

Trade-offs:

* Tight runtime coupling — both client and service must be available simultaneously.
* Reduced availability — if the service is down, the client call fails.
* Potential for cascading failures without resilience patterns like Circuit Breaker.
* Synchronous blocking can limit throughput under high load.

## Related Java Design Patterns

* [Circuit Breaker](https://java-design-patterns.com/patterns/circuit-breaker/): Protects clients from cascading failures when a remote service is unavailable.
* [Ambassador](https://java-design-patterns.com/patterns/ambassador/): Can act as a proxy for remote service calls, adding retry, logging, or monitoring.
* [Gateway](https://java-design-patterns.com/patterns/gateway/): Provides a single entry point that routes RPI calls to the appropriate backend service.

## References and Credits

* [Microservices Patterns: With examples in Java](https://amzn.to/3UyWD5O)
* [Pattern: Remote Procedure Invocation (microservices.io)](https://microservices.io/patterns/communication-style/rpi.html)
* [Spring Boot Documentation](https://spring.io/projects/spring-boot)
Binary file added remote-procedure-invocation/etc/rpi.urm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions remote-procedure-invocation/etc/rpi.urm.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@startuml
package com.iluwatar.rpi {
class App {
+ main(args : String[]) {static}
}
class RpiService {
+ greet(name : String) : String
}
class RpiClient {
- restTemplate : RestTemplate
- baseUrl : String
+ RpiClient(restTemplate : RestTemplate, baseUrl : String)
+ greet(name : String) : String
}
}

RpiClient ..> RpiService : <<HTTP GET /greet>>
@enduml
71 changes: 71 additions & 0 deletions remote-procedure-invocation/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).

The MIT License
Copyright © 2014-2022 Ilkka Seppälä

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

-->
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.iluwatar</groupId>
<artifactId>java-design-patterns</artifactId>
<version>1.26.0-SNAPSHOT</version>
</parent>
<artifactId>remote-procedure-invocation</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<configuration>
<archive>
<manifest>
<mainClass>com.iluwatar.rpi.App</mainClass>
</manifest>
</archive>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
*
* The MIT License
* Copyright © 2014-2022 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.rpi;

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

/**
* Remote Procedure Invocation (RPI) is a communication pattern used in microservices architectures
* where a client sends a synchronous request to a service and waits for a response. Unlike
* message-based communication, RPI uses a direct request/reply protocol — typically REST over HTTP.
*
* <p>In this example, the {@link RpiService} exposes a REST endpoint that returns a greeting
* message. The {@link RpiClient} uses Spring's {@link org.springframework.web.client.RestTemplate}
* to make a synchronous HTTP GET call to the service and retrieve the response.
*
* <p>Key characteristics of RPI:
*
* <ul>
* <li>Synchronous communication — the client blocks until the response arrives.
* <li>Simple and familiar — leverages standard HTTP/REST protocols.
* <li>No intermediate broker — direct client-to-service communication.
* <li>Both client and service must be available at the time of the call (tight runtime coupling).
* </ul>
*
* @see <a href="https://microservices.io/patterns/communication-style/rpi.html">RPI Pattern</a>
*/
@SpringBootApplication
public class App {

/** Program entry point. */
public static void main(String[] args) {
var context = SpringApplication.run(App.class, args);
if (args.length > 0 && "test".equals(args[0])) {
context.close();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
*
* The MIT License
* Copyright © 2014-2022 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.rpi;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.client.RestTemplate;

/**
* The client-side component of the RPI pattern. Uses {@link RestTemplate} to make a synchronous
* HTTP GET request to the remote {@link RpiService} and returns the response. This demonstrates the
* core of RPI — a client blocking on a remote call and waiting for the result.
*/
@Slf4j
public class RpiClient {

private final RestTemplate restTemplate;
private final String baseUrl;

/**
* Creates a new RpiClient.
*
* @param restTemplate the RestTemplate used to perform HTTP calls
* @param baseUrl the base URL of the remote service (e.g. "http://localhost:8080")
*/
public RpiClient(RestTemplate restTemplate, String baseUrl) {
this.restTemplate = restTemplate;
this.baseUrl = baseUrl;
}

/**
* Invokes the remote greeting service with the given name.
*
* @param name the name to send to the remote service
* @return the greeting response from the service
*/
public String greet(String name) {
var url = baseUrl + "/greet?name=" + name;
LOGGER.info("Calling remote service: {}", url);
var response = restTemplate.getForObject(url, String.class);
LOGGER.info("Received response: {}", response);
return response;
}
}
Loading
Loading