Skip to content

Hogwai/spring-cache

Repository files navigation

Spring Cache Showcase

A demonstration project showcasing 4 different caching implementations with Spring Boot, applied to the same CRUD application (Customer).

Implementations

Module Cache type Use case Configuration Port
spring-cache-caffeine Local in-process cache Standalone app, high performance Java (CacheConfig) 8083
spring-cache-redis Distributed cache Microservices, horizontal scaling Java (RedisConfig) 8084
spring-jcache-ehcache Local JCache (JSR-107) Multi-tier cache (heap + off-heap + disk) XML (ehcache.xml) 8081
spring-jcache-hazelcast Distributed JCache (JSR-107) Distributed data grid XML (hazelcast.xml) 8082

Prerequisites

  • Java 21
  • Docker & Docker Compose

Getting started

1. Start the infrastructure

docker-compose up -d

This starts:

  • PostgreSQL 16 on port 5433
  • Redis 7 on port 6379

2. Build the project

./gradlew build

3. Run a module

# Caffeine (local cache)
./gradlew :spring-cache-caffeine:bootRun

# Redis (distributed cache)
./gradlew :spring-cache-redis:bootRun

# Ehcache (local JCache)
./gradlew :spring-jcache-ehcache:bootRun

# Hazelcast (distributed JCache)
./gradlew :spring-jcache-hazelcast:bootRun

Endpoints (identical for each module)

Method URL Description
POST /customers/save-all?number=100 Batch insert customers
POST /customers/save-all?number=100&hibernate=true Batch insert via Hibernate
GET /customers/get-all Get all customers (cached)
PUT /customers/update-all?hibernate=false Batch update (evicts cache)
DELETE /customers/delete-all Delete all customers

Each module also exposes Swagger UI at /swagger-ui.html.

Testing the cache

# 1. Insert data
curl -X POST "http://localhost:8083/customers/save-all?number=100"

# 2. First call: reads from the database
curl http://localhost:8083/customers/get-all

# 3. Second call: reads from cache (faster)
curl http://localhost:8083/customers/get-all

# 4. Update: evicts the cache
curl -X PUT "http://localhost:8083/customers/update-all?hibernate=false"

# 5. Next call: reads from the database again
curl http://localhost:8083/customers/get-all

# 6. Cleanup
curl -X DELETE http://localhost:8083/customers/delete-all

Implementation details

Each module applies the same caching strategy on the service layer via Spring annotations:

  • @Cacheable(value = "customers", key = "#root.methodName") on getAllCustomers() — caches the result; subsequent calls skip the database
  • @CacheEvict(value = "customers", allEntries = true) on updateAllByBatch() — evicts the entire cache so the next read fetches fresh data

The difference between modules lies in the cache provider and its configuration.

Caffeine (local, in-process)

Provider Caffeine via CaffeineCacheManager
Config Java — CacheConfig.java
TTL 30 s (expireAfterWrite)
Eviction Size-based (maximumSize = 10 000) + time-based
Extras recordStats() for hit/miss metrics

Pure Spring Cache abstraction, no XML. Ideal for single-JVM applications needing a fast, lightweight cache.

Redis (distributed)

Provider Redis via RedisCacheManager
Config Java — RedisConfig.java
TTL 30 s (entryTtl)
Serialization JSON (GenericJackson2JsonRedisSerializer) instead of Java serialization
Infra Requires a running Redis instance (see docker-compose.yml)

Same Spring Cache annotations as Caffeine, but the cache is external. Values are stored as human-readable JSON in Redis, making debugging easier.

Ehcache (JCache / JSR-107, local)

Provider Ehcache 3 via JCache (JSR-107)
Config XML — ehcache.xml
TTL 30 s
Tiers Heap (100 entries) → Off-heap (10 MB) → Disk (20 MB, persistent)
Listener CacheEventLogger — logs CREATED, EXPIRED, EVICTED events asynchronously

Multi-tier storage: hot entries live on the heap, overflow goes to off-heap memory, then to persistent disk. The JSR-107 standard means the same annotations work, but configuration is provider-specific XML.

Hazelcast (JCache / JSR-107, distributed)

Provider Hazelcast 5 via JCache (JSR-107)
Config XML — hazelcast.xml
TTL 1 min (expiry policy on CREATED)
Listener CacheEntryListener — logs CREATED, UPDATED, REMOVED, EXPIRED events
Extras Statistics enabled, cluster-aware (distributed data grid)

Hazelcast embeds a distributed data grid in the JVM. Cache entries are automatically replicated across cluster members. The CacheEntryListener implements Factory<CacheEntryListener> as required by the Hazelcast JCache SPI.

Contributors

Languages