本文目录导读:

我将为您提供一个完整的Java分布式缓存实现案例,包含多种主流方案。
基于Redis的分布式缓存实现
Maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
Redis配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
// 使用String序列化器处理key
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
template.setKeySerializer(stringRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
// 使用Jackson序列化器处理value
GenericJackson2JsonRedisSerializer jacksonSerializer = new GenericJackson2JsonRedisSerializer();
template.setValueSerializer(jacksonSerializer);
template.setHashValueSerializer(jacksonSerializer);
template.afterPropertiesSet();
return template;
}
}
缓存服务实现
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
public class CacheServiceImpl implements CacheService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private ObjectMapper objectMapper;
private static final String CACHE_PREFIX = "cache:";
private static final long DEFAULT_EXPIRE_TIME = 3600; // 默认1小时
@Override
public void set(String key, Object value) {
set(key, value, DEFAULT_EXPIRE_TIME);
}
@Override
public void set(String key, Object value, long expireSeconds) {
try {
redisTemplate.opsForValue().set(CACHE_PREFIX + key, value, expireSeconds, TimeUnit.SECONDS);
} catch (Exception e) {
// 异常处理,可以记录日志
throw new CacheOperationException("Failed to set cache: " + key, e);
}
}
@Override
public Object get(String key) {
try {
return redisTemplate.opsForValue().get(CACHE_PREFIX + key);
} catch (Exception e) {
throw new CacheOperationException("Failed to get cache: " + key, e);
}
}
@Override
public <T> T get(String key, Class<T> clazz) {
Object value = get(key);
if (value == null) return null;
try {
return objectMapper.convertValue(value, clazz);
} catch (Exception e) {
throw new CacheOperationException("Failed to convert cache value", e);
}
}
@Override
public boolean delete(String key) {
try {
return Boolean.TRUE.equals(redisTemplate.delete(CACHE_PREFIX + key));
} catch (Exception e) {
throw new CacheOperationException("Failed to delete cache: " + key, e);
}
}
@Override
public boolean expire(String key, long timeout, TimeUnit timeUnit) {
try {
return Boolean.TRUE.equals(redisTemplate.expire(CACHE_PREFIX + key, timeout, timeUnit));
} catch (Exception e) {
throw new CacheOperationException("Failed to expire cache: " + key, e);
}
}
@Override
public boolean exists(String key) {
try {
return Boolean.TRUE.equals(redisTemplate.hasKey(CACHE_PREFIX + key));
} catch (Exception e) {
throw new CacheOperationException("Failed to check cache existence: " + key, e);
}
}
}
缓存管理接口
import java.util.concurrent.TimeUnit;
public interface CacheService {
void set(String key, Object value);
void set(String key, Object value, long expireSeconds);
Object get(String key);
<T> T get(String key, Class<T> clazz);
boolean delete(String key);
boolean expire(String key, long timeout, TimeUnit timeUnit);
boolean exists(String key);
}
public class CacheOperationException extends RuntimeException {
public CacheOperationException(String message, Throwable cause) {
super(message, cause);
}
}
使用Spring Cache注解
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class UserService {
// 查询用户并缓存
@Cacheable(value = "users", key = "#userId")
public User getUserById(Long userId) {
return queryUserFromDatabase(userId);
}
// 更新用户缓存
@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {
updateUserInDatabase(user);
return user;
}
// 删除用户缓存
@CacheEvict(value = "users", key = "#userId")
public void deleteUser(Long userId) {
deleteUserFromDatabase(userId);
}
// 批量清空缓存
@CacheEvict(value = "users", allEntries = true)
public void clearAllUsers() {
// 业务逻辑
}
private User queryUserFromDatabase(Long userId) {
// 模拟数据库查询
return new User(userId, "user" + userId);
}
private void updateUserInDatabase(User user) {
// 模拟数据库更新
}
private void deleteUserFromDatabase(Long userId) {
// 模拟数据库删除
}
}
缓存击穿解决方案 - 互斥锁
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
public class CachePenetrationService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private static final String LOCK_PREFIX = "lock:";
public Object getDataWithMutex(String key, long expireTime) {
// 从缓存获取数据
Object data = redisTemplate.opsForValue().get(key);
if (data != null) {
return data;
}
// 尝试获取分布式锁
String lockKey = LOCK_PREFIX + key;
String requestId = UUID.randomUUID().toString();
boolean gotLock = redisTemplate.opsForValue()
.setIfAbsent(lockKey, requestId, 10, TimeUnit.SECONDS);
if (gotLock) {
try {
// 再次检查缓存(双重检查锁)
data = redisTemplate.opsForValue().get(key);
if (data != null) {
return data;
}
// 查询数据库
data = queryFromDatabase(key);
// 写入缓存
redisTemplate.opsForValue().set(key, data, expireTime, TimeUnit.SECONDS);
return data;
} finally {
// 释放锁
releaseLock(lockKey, requestId);
}
} else {
// 等待重试
try {
Thread.sleep(100);
return getDataWithMutex(key, expireTime);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
}
}
}
private void releaseLock(String lockKey, String requestId) {
// 使用Lua脚本原子性释放锁
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('del', KEYS[1]) " +
"else return 0 end";
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
redisTemplate.execute(redisScript, Collections.singletonList(lockKey), requestId);
}
private Object queryFromDatabase(String key) {
// 模拟数据库查询
return new Object();
}
}
使用Caffeine + Redis二级缓存
Maven依赖
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.1.8</version>
</dependency>
二级缓存实现
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
public class TwoLevelCacheService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 本地缓存(一级缓存)
private Cache<String, Object> localCache;
public TwoLevelCacheService() {
// 初始化本地缓存
localCache = Caffeine.newBuilder()
.maximumSize(10000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.recordStats()
.build();
}
public Object get(String key) {
// 1. 先从本地缓存获取
Object value = localCache.getIfPresent(key);
if (value != null) {
return value;
}
// 2. 本地缓存未命中,从Redis获取
value = redisTemplate.opsForValue().get(key);
if (value != null) {
// 写回本地缓存
localCache.put(key, value);
return value;
}
// 3. Redis未命中,查询数据库
value = queryFromDatabase(key);
if (value != null) {
// 写入两级缓存
redisTemplate.opsForValue().set(key, value, 1, TimeUnit.HOURS);
localCache.put(key, value);
}
return value;
}
public void put(String key, Object value) {
// 更新两级缓存
redisTemplate.opsForValue().set(key, value, 1, TimeUnit.HOURS);
localCache.put(key, value);
}
public void evict(String key) {
// 删除两级缓存
redisTemplate.delete(key);
localCache.invalidate(key);
}
public void clear() {
// 清空所有缓存
Set<String> keys = redisTemplate.keys("*");
if (keys != null && !keys.isEmpty()) {
redisTemplate.delete(keys);
}
localCache.invalidateAll();
}
private Object queryFromDatabase(String key) {
// 模拟数据库查询
return new Object();
}
}
缓存工具类封装
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
@Component
public class CacheUtils {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* 带失效时间的缓存获取
*/
public Object getOrLoad(String key, Supplier<Object> loader, long expireSeconds) {
Object value = redisTemplate.opsForValue().get(key);
if (value != null) {
return value;
}
synchronized (key.intern()) {
// 双重检查
value = redisTemplate.opsForValue().get(key);
if (value != null) {
return value;
}
value = loader.get();
if (value != null) {
redisTemplate.opsForValue().set(key, value, expireSeconds, TimeUnit.SECONDS);
}
return value;
}
}
/**
* 布隆过滤器防止缓存穿透
*/
public boolean mightContain(String key) {
// 使用Redis的BitMap实现简单的布隆过滤器
return Boolean.TRUE.equals(redisTemplate.opsForValue()
.getBit("bloom:" + key.hashCode(), hash(key)));
}
private long hash(String key) {
return Math.abs(key.hashCode() % 1024);
}
}
监控和统计
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
public class CacheMonitorService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public Map<String, Object> getCacheStats() {
Map<String, Object> stats = new HashMap<>();
// 获取Redis内存信息
Properties memoryInfo = redisTemplate.getConnectionFactory()
.getConnection().info("memory");
stats.put("memory", memoryInfo);
// 获取所有缓存key数量
Set<String> keys = redisTemplate.keys("cache:*");
stats.put("cacheKeys", keys != null ? keys.size() : 0);
// 其他统计信息
return stats;
}
}
这个分布式缓存案例包含了:
- Redis基本缓存操作
- Spring Cache注解支持
- 缓存击穿防护(互斥锁)
- 多级缓存(本地+Redis)
- 缓存工具类封装
- 缓存监控
根据实际需求,您可以选择合适的方案组合使用,建议在高并发场景下考虑使用二级缓存,在数据一致性要求高的场景注意缓存策略的设计。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播