Spring Boot Reactive Remote Caching
What You Will Learn
How to use Spring Boot’s @EnableCaching with Project Reactor (Mono) and the Infinispan Spring Boot remote starter for reactive caching against an Infinispan Server.
Prerequisites
-
Java 17+
-
Spring Boot
-
An Infinispan Server running on
localhost:11222(or Docker/Podman available for Testcontainers)
Step 1: Add Dependencies
Add the Infinispan Spring Boot remote starter with Spring WebFlux:
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-spring-boot4-starter-remote</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.infinispan.protostream</groupId>
<artifactId>protostream-processor</artifactId>
</dependency>
Step 2: Enable Reactive Caching
In application.properties, enable the reactive mode:
infinispan.remote.server-list=127.0.0.1:11222
infinispan.remote.reactive=true
Step 3: Return Mono from Cached Methods
Annotate methods that return Mono with @Cacheable. The Infinispan reactive cache adapter handles the subscription:
@Component
@CacheConfig(cacheNames = Data.BASQUE_NAMES_CACHE)
public class BasqueNamesRepository {
private static final Logger logger = Logger.getLogger(MethodHandles.lookup().lookupClass().getName());
private static Map<String, BasqueName> database = createDB();
@Cacheable
public Mono<BasqueName> findById(String id) {
logger.info("Call database to FIND name by id '" + id + "'");
return Mono.fromCallable(() -> database.get(id));
}
Step 4: Configure the Remote Cache and Schema
Register the Protobuf schema and cache configuration:
@Configuration
public class InfinispanConfiguration {
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public InfinispanRemoteCacheCustomizer configurer() {
return b -> {
String host = TutorialsConnectorHelper.HOST;
int port = TutorialsConnectorHelper.SINGLE_PORT;
if (TutorialsConnectorHelper.INFINISPAN_CONTAINER != null) {
port = TutorialsConnectorHelper.INFINISPAN_CONTAINER.getFirstMappedPort();
}
b.addServer().host(host).port(port);
b.security().authentication()
.username(TutorialsConnectorHelper.USER)
.password(TutorialsConnectorHelper.PASSWORD);
System.out.println(String.format("Connect to the Infinispan Console " +
"by login to http://localhost:%d with %s and %s", port,
TutorialsConnectorHelper.USER,
TutorialsConnectorHelper.PASSWORD));
URI cacheConfigUri;
try {
cacheConfigUri = this.getClass().getClassLoader().getResource("basquesNamesCache.xml").toURI();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
b.remoteCache(Data.BASQUE_NAMES_CACHE)
.configurationURI(cacheConfigUri);
b.remoteCache(Data.BASQUE_NAMES_CACHE).marshaller(ProtoStreamMarshaller.class);
// Add marshaller in the client, the class is generated from the interface in compile time
b.addContextInitializer(new BasquesNamesSchemaBuilderImpl());
};
}
}
Step 5: Run the Tutorial
mvn spring-boot:run
The application periodically looks up Basque names. Watch the logs: the first lookup for each id logs "Call database", while subsequent lookups return from the Infinispan cache without the log message.
What’s Next
-
Spring Boot remote caching for the non-reactive version
-
Spring Boot embedded caching for caching without a server


