skip to content

How do you configure CaffeineCacheManager, and how does JCacheCacheManager differ as a provider bridge?

level: middleimportance: should knowfreq 40%

answer

  1. Caffeine: one spec for all caches
  2. setCaffeine / setCacheSpecification string
  3. constructor names => fixed, no dynamic
  4. asyncCacheMode for CompletableFuture
  5. JCache = adapt javax.cache provider config

basics

~20 s

Configure CaffeineCacheManager by giving it a Caffeine builder or a spec string (e.g. maximumSize, expireAfterWrite). JCacheCacheManager instead wraps a JSR-107 javax.cache.CacheManager from a provider like Ehcache 3, so the provider's own config file drives behaviour.

solid answer

~40 s

CaffeineCacheManager applies one Caffeine configuration to every cache it creates. You set it via setCaffeine(Caffeine.newBuilder().maximumSize(...).expireAfterWrite(...)), setCaffeineSpec(CaffeineSpec.parse(...)), or a plain string with setCacheSpecification("maximumSize=500,expireAfterWrite=10m"). Passing cache names to the constructor fixes the set and disables dynamic creation; otherwise caches are created on demand. It can also run in async mode for reactive/CompletableFuture returns. JCacheCacheManager is different in kind: it doesn't store anything itself — it adapts a standardized javax.cache.CacheManager (JSR-107). You bring a compliant provider (Ehcache 3, Hazelcast, Infinispan), configure per-cache policies in that provider's native config, and Spring wraps each javax.cache.Cache. Caffeine gives per-manager Java config; JCache gives vendor-neutral, provider-driven config and features like listeners and standardized statistics.

code

java · 16 lines
java
@Bean
public CacheManager caffeine() {
    CaffeineCacheManager mgr = new CaffeineCacheManager();
    mgr.setCacheSpecification("maximumSize=1000,expireAfterWrite=10m,recordStats");
    // per-cache override sharing the same manager:
    mgr.registerCustomCache("shortLived",
        Caffeine.newBuilder().expireAfterWrite(Duration.ofSeconds(30)).build());
    return mgr;
}

@Bean
public CacheManager jcache() {
    javax.cache.CacheManager jsr107 =
        Caching.getCachingProvider().getCacheManager(); // e.g. Ehcache 3 provider
    return new JCacheCacheManager(jsr107);
}

go deeper

for a junior

Know Caffeine is configured with a spec string and JCache wraps a JSR-107 provider.

for a middle

Configure Caffeine three ways and explain the single-spec limitation and JCache adapter role.

for a senior

Handle per-cache TTL strategies, async mode, and provider portability trade-offs.

for a principal

Design multi-provider topologies and standardize on JSR-107 vs local Caffeine across services.

## CaffeineCacheManager configuration `CaffeineCacheManager` (in `spring-context-support`) adapts the Caffeine library. Key point: **one Caffeine specification is shared by all caches this manager builds** — you cannot give two caches different TTLs from a single CaffeineCacheManager unless you register pre-built native caches. Ways to configure: - `setCaffeine(Caffeine<Object,Object> builder)` — full programmatic control: `maximumSize`, `maximumWeight`+`weigher`, `expireAfterWrite`, `expireAfterAccess`, `refreshAfterWrite` (needs a `CacheLoader`), `weakKeys`, `softValues`, `recordStats`. - `setCaffeineSpec(CaffeineSpec)` — a parsed spec object. - `setCacheSpecification(String)` — string form, e.g. `"maximumSize=1000,expireAfterWrite=5m,recordStats"`. - Constructor names, e.g. `new CaffeineCacheManager("a","b")`, **fix** the cache set and turn off dynamic creation; the no-arg constructor leaves it dynamic. - `setAllowNullValues(boolean)` — whether a `null` return is cached (default true; stored as an internal placeholder). - `setAsyncCacheMode(true)` — backs caches with Caffeine `AsyncCache`, required for `@Cacheable` on methods returning `CompletableFuture`/reactive types. - To give different caches different policies from one manager, register native caches with `registerCustomCache(name, nativeCaffeineCache)`. Spring Boot can auto-configure this: with Caffeine on the classpath and `spring.cache.type=caffeine`, `spring.cache.caffeine.spec=...` feeds the spec. ## JCacheCacheManager (JSR-107) as a bridge JSR-107 (`javax.cache`, aka JCache) is a **standard caching API**. Providers implementing it include Ehcache 3, Hazelcast, Infinispan, and others. Spring's `JCacheCacheManager` does not implement a cache store; it **adapts an existing `javax.cache.CacheManager`**: 1. A `javax.cache.spi.CachingProvider` is discovered (`Caching.getCachingProvider()`). 2. It produces a `javax.cache.CacheManager`, typically configured from the provider's native config (e.g. an Ehcache 3 XML at a URI) or programmatically with `MutableConfiguration`. 3. Spring's `JCacheCacheManager` wraps it, exposing each `javax.cache.Cache` as a Spring `Cache`. Because config lives in the JCache provider, **per-cache TTL, expiry policies, listeners, and statistics are defined the JSR-107 way**, not through Spring. This gives vendor portability: swap Ehcache for Hazelcast by changing the provider, not your Spring code. > Note: this JCacheCacheManager is Spring's cache-abstraction adapter (`org.springframework.cache.jcache.JCacheCacheManager`). It is distinct from JSR-107's own `@CacheResult` annotations, which Spring can also honour separately. ## When to choose which - **Caffeine**: single JVM, want the fastest local cache, config in Java/properties, no distribution. Default modern local choice. - **JCache**: you need a standardized/portable provider, richer per-cache policies, JMX statistics, or a provider that also offers clustering (Hazelcast/Infinispan). ## Gotchas - Sharing one Caffeine spec across all caches surprises people who expect per-name TTL; use `registerCustomCache` or multiple managers (routed by `CompositeCacheManager`/`cacheResolver`). - `refreshAfterWrite` needs a `CacheLoader`; without one it behaves like no refresh. - Async mode is mandatory for `CompletableFuture`-returning cached methods; forgetting it causes type errors. - With JCache, forgetting to pre-define a cache in the provider can throw when Spring requests an unknown name (depends on provider's dynamic-cache support).

  • How do you give two caches different TTLs when both are managed by Caffeine?
    One CaffeineCacheManager shares a single spec, so either register per-name native caches via registerCustomCache, or run multiple CaffeineCacheManagers routed by a CompositeCacheManager or a CacheResolver.
  • Does JCacheCacheManager store cache entries itself?
    No. It's an adapter over a JSR-107 javax.cache.CacheManager; the actual store, TTLs, and policies come from the underlying provider (Ehcache 3, Hazelcast, etc.).

saying these in an interview costs you the question

  • Believing CaffeineCacheManager supports independent per-cache specs from a single manager without extra work
  • Thinking JCacheCacheManager is its own cache store rather than an adapter
  • Forgetting asyncCacheMode is required for CompletableFuture-returning cached methods

context