Quarkus Infinispan Embedded

The new Infinispan Embedded Quarkus extension simplifies using Infinispan as an embedded data grid or cache in Quarkus applications.

  • Embedded Infinispan: Run Infinispan in the same process as your application, eliminating the need for a standalone server.

  • Seamless Quarkus Integration: Optimized for Quarkus, providing fast startup, low memory footprint, and simplified configuration.

  • Flexible Caching and Data Grid Capabilities: Easily store and manage data in-memory for high performance and scalability.

This extension is ideal for developers who want to build high-speed, lightweight applications without the overhead of managing external data services.

Quick Overview

To incorporate Quarkus Infinispan Embedded into your Quarkus project, add the following Maven dependency:

<dependency>
    <groupId>io.quarkiverse.infinispan</groupId>
    <artifactId>quarkus-infinispan-embedded</artifactId>
    <version>1.0.2</version>
</dependency>

Injecting EmbeddedCacheManager

In your application, you can inject org.infinispan.manager.EmbeddedCacheManager to interact completely with Infinispan embedded.

package io.quarkiverse.infinispan.embedded.samples;

import jakarta.inject.Inject;

import org.infinispan.Cache;
import org.infinispan.commons.api.CacheContainerAdmin;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.manager.EmbeddedCacheManager;

import io.quarkus.logging.Log;
import io.quarkus.runtime.QuarkusApplication;
import io.quarkus.runtime.annotations.QuarkusMain;

@QuarkusMain
public class MyServiceExample implements QuarkusApplication {

    @Inject
    private EmbeddedCacheManager cacheManager; (1)

    @Override
    public int run(String... args) {
        Configuration config = new ConfigurationBuilder()
                .clustering().cacheMode(CacheMode.DIST_ASYNC).build();
        Log.info(cacheManager.administration() (2)
                .withFlags(CacheContainerAdmin.AdminFlag.VOLATILE)
                .getOrCreateCache("mycache", config));
        Cache<String, String> mycache = cacheManager.getCache("mycache");
        mycache.put("greeting", "Hello world!");
        Log.info(mycache.get("greeting"));
        return 0;
    }
}
1 @Inject is used to inject the EmbeddedCacheManager into your bean.
2 Use the EmbeddedCacheManager. The scope of the bean is @ApplicationScoped

Injecting embedded caches

In your application, you can inject either org.infinispan.Cache or org.infinispan.AdvancedCache to interact with an Infinispan embedded cache instance.

package io.quarkiverse.infinispan.embedded.samples;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

import org.infinispan.Cache;

import io.quarkiverse.infinispan.embedded.Embedded;

@ApplicationScoped
public class CacheInjectionExample {

    @Inject (1)
    @Embedded("mycache") (2)
    private Cache<String, String> cache;

    public void addValue(String key, String value) {
        cache.put("greeting", "Hello world!"); (3)
    }
}
1 @Inject is used to inject the cache into your bean.
2 The @Embedded("cache-name") specifies the cache name. Specifies the name of the cache. If the cache does not exist, it will be created on first access with default configuration (either local or distributed, depending on setup)
3 Use the Cache. The scope of the bean is @ApplicationScoped

Caching annotations

This extension implements the QuarkusCache extension to integrate seamlessly with the Quarkus caching. By providing a custom implementation backed by Infinispan’s embedded cache, it allows developers to leverage Quarkus’s caching annotations (e.g., @CacheResult, @CacheInvalidate) while benefiting from the robustness and flexibility of Infinispan embedded. This ensures compatibility with the broader Quarkus ecosystem and enables declarative caching for local or distributed cache scenarios out of the box.

package io.quarkiverse.infinispan.embedded.samples;

import static java.util.Objects.requireNonNull;

import java.util.concurrent.ThreadLocalRandom;

import jakarta.enterprise.context.ApplicationScoped;

import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.Proto;
import org.infinispan.protostream.annotations.ProtoSchema;

import io.quarkus.cache.CacheInvalidate;
import io.quarkus.cache.CacheInvalidateAll;
import io.quarkus.cache.CacheResult;
import io.quarkus.logging.Log;

@ApplicationScoped (1)
public class WeatherService {
    ThreadLocalRandom random = ThreadLocalRandom.current();

    @Proto (2)
    public record Weather(String temperature, String windSpeed, String windDirection) {
        @ProtoSchema(includeClasses = { Weather.class }, (3)
                schemaPackageName = "io.quarkiverse.weather")
        public interface WeatherSchema extends GeneratedSchema {
        }
    }

    @CacheResult(cacheName = "weather") (4)
    public Weather retrieve(String city) {
        requireNonNull(city);
        String temperature = String.format("%.1f", random.nextDouble() * 40); // Random temperature between 0 and 40
        String windSpeed = String.format("%dkm", random.nextInt(30) + 10); // Random wind speed between 10 and 40 km/h
        String[] directions = { "North", "South", "East", "West", "Northwest", "Southeast" };
        String windDirection = directions[random.nextInt(directions.length)]; // Random wind direction
        return new Weather(temperature, windSpeed, windDirection);
    }

    @CacheInvalidateAll(cacheName = "weather") (5)
    public void clearAll() {
        Log.info("Clearing weather cache");
    }

    @CacheInvalidate(cacheName = "weather") (6)
    public void clearWeather(String city) {
        Log.info("Clear city: " + city);
    }
}
1 Declares the class as an @ApplicationScoped CDI bean, ensuring a single instance throughout the app.
2 Marks the Weather record for Protobuf serialization.
3 Declares the Protobuf schema, including the Weather class and setting the schema package.
4 Caches the result of retrieve() using the weather cache.
5 Invalidates all entries in the weather cache.
6 Invalidates the specific cache entry for a given city.

If the cache does not exist, it will be created on first access with default configuration (either local or distributed, depending on setup)

Check the cache-sample under the samples folder.

Providing Infinispan Embedded configuration

To customize the embedded Infinispan cache configuration, use the property quarkus.infinispan-embedded.xml-config.

<infinispan> (1)
		<cache-container name="default" statistics="true"> (2)
				<local-cache name="todolist"> (3)
						<persistence passivation="false"> (4)
								<file-store shared="false">
									<data path="target/data" />
									<index path="target/index" />
								</file-store>
							</persistence>
						</local-cache>
					</cache-container>
				</infinispan>
1 Root element for Infinispan configuration.
2 Declares a cache container named "default" with statistics enabled.
3 Defines a local cache called "todolist".
4 Disabled passivation and configures a file-based persistent store.
quarkus.infinispan-embedded.xml-config=caches.xml (1)
1 Quarkus loads the Infinispan configuration from the specified XML file (caches.xml)

Check the persisted-cache-sample under the samples folder.

In this example, the local cache will use file persistence to persist the state.

Default caches configuration

When no explicit configuration is provided for a cache, Quarkus automatically applies sensible defaults based on the context. It defines two built-in configuration names:

  • DEFAULT_LOCAL_QUARKUS_CACHE_CONFIGURATION for local caches

  • DEFAULT_CLUSTERED_QUARKUS_CACHE_CONFIGURATION for distributed caches.

These default configurations are registered at runtime and applied on first access to any undefined cache. The local configuration uses CacheMode.LOCAL for single-node setups, while the clustered configuration uses CacheMode.DIST_SYNC with Protobuf (application/x-protostream) as the media type, ensuring compatibility with remote marshalling. This approach simplifies development by reducing boilerplate, while still supporting custom XML-based configurations when needed.

Configuration Settings

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

The configured Infinispan embedded xml file which is used by the managed EmbeddedCacheManager and its Caches

Environment variable: QUARKUS_INFINISPAN_EMBEDDED_XML_CONFIG

string

Sets a cluster with defaults.

Environment variable: QUARKUS_INFINISPAN_EMBEDDED_CLUSTERED

boolean

true