Implementing a Two‑Level Cache System with Guava and Redis in Java
This article explains how to build a two‑level caching solution in Java by defining a generic cache interface, implementing a local Guava‑based cache and a distributed Redis cache, configuring Spring Boot integration, handling versioned keys for timely expiration, and providing sample code and unit tests.
1. General Cache Interface
Cache algorithms such as FIFO, LFU, and LRU are introduced, followed by a generic CacheProviderService interface that defines methods for getting, setting, removing, and checking cache entries with optional expiration and functional callbacks.
2. Local Cache (Guava)
Guava is used as an in‑process cache. The required Maven dependency is added, and a LocalCacheProviderImpl class implements the cache interface using CacheBuilder with size limits and expiration policies. The implementation includes overloaded get methods that accept a Function to load missing values, as well as set, remove, and contains operations.
package com.power.demo.cache.contract;
import java.util.function.Function;
/**
* Cache provider interface
*/
public interface CacheProviderService {
<T extends Object> T get(String key);
<T extends Object> T get(String key, Function<String, T> function);
<T extends Object, M extends Object> T get(String key, Function<M, T> function, M funcParm);
<T extends Object> T get(String key, Function<String, T> function, Long expireTime);
<T extends Object, M extends Object> T get(String key, Function<M, T> function, M funcParm, Long expireTime);
<T extends Object> void set(String key, T obj);
<T extends Object> void set(String key, T obj, Long expireTime);
void remove(String key);
boolean contains(String key);
}3. Distributed Cache (Redis)
Redis is introduced as a high‑performance key‑value store. Maven dependency spring-boot-starter-data-redis is added, and a RedisConfig class configures the CacheManager and RedisTemplate with appropriate serializers.
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
return RedisCacheManager.create(connectionFactory);
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setKeySerializer(new StringRedisSerializer());
template.setConnectionFactory(factory);
return template;
}
}The RedisCacheProviderImpl implements the same interface, using RedisTemplate to perform get, set (with optional expiration), remove, and contains operations, and supports functional loading of missing entries.
4. Cache Versioning and Two‑Level Cache
A PowerCacheBuilder class aggregates multiple CacheProviderService instances (local first, then Redis) and adds version control for Redis keys. Methods generate versioned keys, reset the version, and ensure that stale data can be invalidated across distributed nodes.
@Configuration
@ComponentScan(basePackages = AppConst.BASE_PACKAGE_NAME)
public class PowerCacheBuilder {
@Autowired @Qualifier("localCacheService")
private CacheProviderService localCacheService;
@Autowired @Qualifier("redisCacheService")
private CacheProviderService redisCacheService;
// ... initialization, getCacheProviders(), get(), set(), remove(), contains()
public String generateVerKey(String key) { /* append version from Redis */ }
public String resetCacheVersion() { /* generate new UUID version and store in Redis */ }
}5. Unit Test Example
A JUnit test demonstrates obtaining the cache version, generating a versioned key, storing a GoodsVO object, retrieving it, resetting the version, and verifying that objects stored under the new version are still accessible.
@Test
public void testCacheVersion() throws Exception {
String version = cacheBuilder.getCacheVersion();
String cacheKey = cacheBuilder.generateVerKey("goods778899");
GoodsVO goodsVO = new GoodsVO();
// set fields ...
cacheBuilder.set(cacheKey, goodsVO);
GoodsVO goodsVO1 = cacheBuilder.get(cacheKey);
Assert.assertNotNull(goodsVO1);
version = cacheBuilder.resetCacheVersion();
cacheKey = cacheBuilder.generateVerKey("goods112233");
cacheBuilder.set(cacheKey, goodsVO);
GoodsVO goodsVO2 = cacheBuilder.get(cacheKey);
Assert.assertNotNull(goodsVO2);
Assert.assertTrue(goodsVO1.getGoodsId().equals(goodsVO2.getGoodsId()));
}6. Conclusion
The article provides a complete, production‑ready two‑level caching framework for Spring Boot applications, covering cache algorithms, interface design, Guava local cache, Redis distributed cache, configuration, versioned keys for timely expiration, and testing, illustrating how Java developers can efficiently improve system performance.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
