Caching in Java: Redis, Caffeine, Ehcache, and JCache
Caching is one of the key tools for improving the performance of Java applications. It reduces response time, lowers the load on databases and external APIs. In this article, we will cover three popular solutions: Redis (external distributed cache), Caffeine (high-performance in-memory cache), and Ehcache (hybrid cache with disk support). We will also look at the JCache (JSR 107) standard, which unifies working with caches.
Why is caching needed in Java?
Main use cases:
- Reducing latency — data from the cache is returned in microseconds, not milliseconds (as with a database query).
- Reducing load — the cache protects the database from repeated queries.
- Saving resources — fewer calls to external services means lower infrastructure costs.
1. Redis — distributed cache for microservices
Redis is an in-memory data store often used as a distributed cache. It supports various data structures: strings, hashes, lists, sets. For Java, there are two main clients: Jedis and Lettuce (recommended for Spring Boot).
Example of connecting via Spring Data Redis:
@Configurationpublic class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); return template; }}
@Servicepublic class UserService { @Autowired private RedisTemplate<String, Object> redisTemplate;
public User getUserById(String id) { String key = "user:" + id; User cached = (User) redisTemplate.opsForValue().get(key); if (cached != null) return cached;
User user = database.findUserById(id); // expensive query redisTemplate.opsForValue().set(key, user, 10, TimeUnit.MINUTES); return user; }}Pros of Redis: distributed, TTL support, pub/sub, persistence. Cons: network latency, server memory consumption.
2. Caffeine — ultra-fast in-memory cache
Caffeine is a library for local caching based on the W-TinyLFU algorithm. It provides nearly 100% hit rate with minimal memory consumption. Ideal for single-threaded and multi-threaded applications.
Example of using Caffeine:
Cache<String, User> cache = Caffeine.newBuilder() .expireAfterWrite(5, TimeUnit.MINUTES) .maximumSize(10_000) .recordStats() .build();
public User getUser(String id) { return cache.get(id, key -> database.findUserById(key));}
// Getting statisticsCacheStats stats = cache.stats();System.out.println("Hit rate: " + stats.hitRate());Pros of Caffeine: minimal latency (nanoseconds), built-in statistics, automatic eviction of old entries. Cons: local cache only, not suitable for distributed systems.
3. Ehcache — hybrid cache with disk storage
Ehcache is one of the oldest caching libraries for Java. It supports in-memory and disk caching, as well as clustering via Terracotta. Often used in conjunction with Hibernate.
Example of Ehcache 3 configuration (XML):
<config xmlns:xsi="http://www.w3.org Also in library
Working with S3 and Cloud Storage in Node.js: @aws-sdk/client-s3 Library
Working with CSV in PHP: PhpSpreadsheet Library
Behat PHP Guide: Complete Tutorial with Examples
Swift QR Code Generator: Core Image, CIFilter and Custom Solutions
Generating PDF Reports in Swift for iOS and macOS with PDFKit and Core Graphics