Infinispan implements the JCache API (also known as JSR-107 and javax.cache).
1. Using the JCache (JSR-107) API
Infinispan provides a fully compliant implementation of the JCache (JSR-107) specification, the standard Java API for temporary caching. You can use the JCache API as a portable caching layer that works across different cache providers.
By coding against the javax.cache API, your application remains portable across JCache-compliant implementations.
|
The JCache specification (JSR-107) is no longer under active development. It was not part of Java EE, has not been adopted by Jakarta EE, and the expert group is no longer active. While Infinispan continues to support the JCache API, no further evolution of the specification is expected. For new projects, consider using the Infinispan native caching API or other actively maintained alternatives, which offer richer functionality and continued development. |
1.1. JCache Dependencies
Add the following dependencies to your pom.xml to use the JCache API with Infinispan:
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-jcache</artifactId>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</dependency>
When these dependencies are on the classpath, Infinispan is automatically discovered as the JCache caching provider through the standard java.util.ServiceLoader mechanism.
1.2. Creating and Using JCache Caches
Create a JCache cache using the standard javax.cache API with Infinispan as the caching provider.
-
Obtain a
CachingProviderandCacheManager. -
Configure a cache with
MutableConfiguration. -
Create the cache and perform operations.
import javax.cache.Cache;
import javax.cache.CacheManager;
import javax.cache.Caching;
import javax.cache.configuration.MutableConfiguration;
import javax.cache.spi.CachingProvider;
// Obtain the JCache CachingProvider. Infinispan is automatically
// discovered when infinispan-jcache is on the classpath.
CachingProvider cachingProvider = Caching.getCachingProvider();
CacheManager cacheManager = cachingProvider.getCacheManager();
// Configure a cache with key and value types.
MutableConfiguration<String, String> configuration = new MutableConfiguration<>();
configuration.setTypes(String.class, String.class);
// Create a named cache with the configuration.
Cache<String, String> cache = cacheManager.createCache("myCache", configuration);
After you create a cache, you can store and retrieve values:
// Store a value
cache.put("key", "value");
// Retrieve the value
String value = cache.get("key");
System.out.printf("key = %s%n", value);
When you are finished, close the CacheManager and CachingProvider to release resources:
cacheManager.close();
cachingProvider.close();
1.3. Configuring Read-Through and Write-Through
JCache supports read-through and write-through caching to automatically load and persist cache entries using a CacheLoader and CacheWriter.
1.3.1. Read-through
With read-through enabled, Infinispan invokes the CacheLoader to load entries from an external store on cache misses.
Read-through is only triggered by get(), getAll(), and invoke() operations.
import javax.cache.Cache;
import javax.cache.CacheManager;
import javax.cache.Caching;
import javax.cache.configuration.FactoryBuilder;
import javax.cache.configuration.MutableConfiguration;
import javax.cache.spi.CachingProvider;
CachingProvider cachingProvider = Caching.getCachingProvider();
CacheManager cacheManager = cachingProvider.getCacheManager();
MutableConfiguration<String, String> configuration = new MutableConfiguration<>();
configuration.setTypes(String.class, String.class);
configuration.setReadThrough(true);
configuration.setCacheLoaderFactory(
FactoryBuilder.factoryOf(MyCacheLoader.class));
Cache<String, String> cache = cacheManager.createCache("readThroughCache", configuration);
1.3.2. Write-through
With write-through enabled, Infinispan invokes the CacheWriter to persist entries to an external store on cache mutations.
import javax.cache.Cache;
import javax.cache.CacheManager;
import javax.cache.Caching;
import javax.cache.configuration.FactoryBuilder;
import javax.cache.configuration.MutableConfiguration;
import javax.cache.spi.CachingProvider;
CachingProvider cachingProvider = Caching.getCachingProvider();
CacheManager cacheManager = cachingProvider.getCacheManager();
MutableConfiguration<String, String> configuration = new MutableConfiguration<>();
configuration.setTypes(String.class, String.class);
configuration.setWriteThrough(true);
configuration.setCacheWriterFactory(
FactoryBuilder.factoryOf(MyCacheWriter.class));
Cache<String, String> cache = cacheManager.createCache("writeThroughCache", configuration);
|
In the Infinispan JCache implementation, |
1.4. JCache Read-Through and Write-Through Behavior
When using the JCache (JSR-107) API with Infinispan, read-through and write-through interact with the underlying persistence layer through CacheLoader and CacheWriter adapters.
Read-through uses CacheLoader to load entries from an external store on cache misses.
Write-through uses CacheWriter to persist entries to an external store on cache mutations.
|
Read-through and write-through behavior is not fully consistent across all JCache operations. The following table documents the current behavior of each operation for reference. |
| Operation | Read-through (CacheLoader) | Write-through (CacheWriter) | Notes |
|---|---|---|---|
|
Conditional on |
Always enabled |
CacheLoader called for missing entries |
|
Conditional on |
Always enabled |
Same as |
|
Always skip |
N/A |
Spec: "only the cache is checked" |
|
Always skip |
Always enabled |
No |
|
Always skip |
Always enabled |
No |
|
Conditional on |
Always enabled |
|
|
Always skip |
Always enabled |
No |
|
Always skip |
Always enabled |
No |
|
Always skip |
Always enabled |
No |
|
Always skip |
Always enabled |
No |
|
Always skip |
Always enabled |
No |
|
Always skip |
Always enabled |
No |
|
Always skip |
Always enabled |
No |
|
Always skip |
Always enabled |
|
|
Always enabled |
Always enabled |
Direct cache API; bypasses functional map |
|
Conditional on |
Always enabled |
Read-through via |
|
Conditional on |
Always enabled |
Same as |
|
N/A |
Always enabled |
Spec: "without notifying listeners or CacheWriters"; clears both cache and store |
"Always enabled" in the write-through column means that writes always go to the store regardless of the isWriteThrough() setting.
This applies both when a JCache CacheWriterFactory is configured and when a persistence store is defined directly in the Infinispan configuration (for example, file-based, JDBC, or RocksDB stores).
Conditional operations such as putIfAbsent, replace, and remove(K, V) only trigger write-through when the mutation actually occurs.
For example, replace(K, V) only writes to the store if the entry already exists in memory.
None of these conditional or previous-value-returning operations (getAndPut, getAndRemove, getAndReplace, putIfAbsent, replace, remove(K, V)) trigger read-through.
Their existence and value checks only see entries currently in memory.
This is consistent with the JSR-107 specification, which restricts read-through to get(), getAll(), and invoke().