public class SynchronizedCache implements Cache {
private final Cache delegate;
public SynchronizedCache(Cache delegate) {
this.delegate = delegate;
}
@Override
public synchronized void putObject(Object key, Object value) {
delegate.putObject(key, value);
}
@Override
public synchronized Object getObject(Object key) {
return delegate.getObject(key);
}
@Override
public synchronized Object removeObject(Object key) {
return delegate.removeObject(key);
}
@Override
public synchronized void clear() {
delegate.clear();
}
// 其他方法委托给delegate
}
设计要点:所有修改操作都需要同步,但同步粒度较粗,适合并发量不高的场景。
2. LoggingCache:缓存命中率监控
public class LoggingCache implements Cache {
private final Cache delegate;
private int hits = 0;
private int requests = 0;
public LoggingCache(Cache delegate) {
this.delegate = delegate;
}
@Override
public Object getObject(Object key) {
requests++;
Object value = delegate.getObject(key);
if (value != null) {
hits++;
}
if (requests % 100 == 0) { // 每100次请求输出日志
logHitRatio();
}
return value;
}
private void logHitRatio() {
double ratio = (double) hits / requests * 100;
System.out.printf("缓存命中率: %.2f%% (命中: %d, 总请求: %d)%n",
ratio, hits, requests);
}
}
监控价值:通过命中率分析缓存效果,指导缓存策略优化。
3. SerializedCache:对象序列化与副本保护
这是二级缓存中最关键的装饰器,解决对象共享的核心问题:
public class SerializedCache implements Cache {
private final Cache delegate;
public SerializedCache(Cache delegate) {
this.delegate = delegate;
}
@Override
public void putObject(Object key, Object value) {
if (value == null || value instanceof Serializable) {
delegate.putObject(key, serialize((Serializable) value));
} else {
throw new CacheException("缓存对象必须实现Serializable接口");
}
}
@Override
public Object getObject(Object key) {
Object value = delegate.getObject(key);
return value != null ? deserialize((byte[]) value) : null;
}
private byte[] serialize(Serializable value) {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(value);
return bos.toByteArray();
} catch (IOException e) {
throw new CacheException("序列化失败", e);
}
}
private Serializable deserialize(byte[] value) {
try (ByteArrayInputStream bis = new ByteArrayInputStream(value);
ObjectInputStream ois = new ObjectInputStream(bis)) {
return (Serializable) ois.readObject();
} catch (Exception e) {
throw new CacheException("反序列化失败", e);
}
}
}
为什么必须使用SerializedCache?
对象隔离:不同SqlSession获取的是不同对象实例,避免并发修改冲突
深度复制:确保缓存对象的完整性,防止浅拷贝带来的数据不一致
跨JVM支持:为分布式缓存奠定基础
4. LruCache:内存资源智能管理
public class LruCache implements Cache {
private final Cache delegate;
private final LinkedHashMap
LRU算法精髓:通过LinkedHashMap的访问顺序特性,自动维护最近使用顺序。
5. BlockingCache:防止缓存击穿的保护盾
public class BlockingCache implements Cache {
private final Cache delegate;
private final ConcurrentHashMap locks;
public BlockingCache(Cache delegate) {
this.delegate = delegate;
this.locks = new ConcurrentHashMap<>();
}
@Override
public Object getObject(Object key) {
acquireLock(key);
try {
return delegate.getObject(key);
} finally {
releaseLock(key);
}
}
@Override
public void putObject(Object key, Object value) {
try {
delegate.putObject(key, value);
} finally {
releaseLock(key);
}
}
private void acquireLock(Object key) {
Lock lock = locks.computeIfAbsent(key, k -> new ReentrantLock());
lock.lock();
}
private void releaseLock(Object key) {
Lock lock = locks.get(key);
if (lock != null) {
lock.unlock();
locks.remove(key); // 清理空闲锁
}
}
}
防击穿原理:当多个线程同时查询同一个不存在的数据时,只有一个线程会访问数据库,其他线程等待结果。
三、CacheBuilder:装饰器的灵活组合器
public class CacheBuilder {
private Cache delegate;
public CacheBuilder(Cache delegate) {
this.delegate = new PerpetualCache("default");
}
public CacheBuilder size(int size) {
this.delegate = new LruCache(delegate, size);
return this;
}
public CacheBuilder blocking() {
this.delegate = new BlockingCache(delegate);
return this;
}
public CacheBuilder serialized() {
this.delegate = new SerializedCache(delegate);
return this;
}
public CacheBuilder logging() {
this.delegate = new LoggingCache(delegate);
return this;
}
public CacheBuilder synchronized() {
this.delegate = new SynchronizedCache(delegate);
return this;
}
public Cache build() {
return delegate;
}
}
// 使用示例
Cache cache = new CacheBuilder(new PerpetualCache("userCache"))
.size(1000)
.serialized()
.blocking()
.logging()
.build();
建造者模式优势:通过链式调用,直观地组合各种缓存特性。
四、装饰器执行顺序的架构考量
装饰器的包装顺序直接影响缓存行为:
正确的顺序设计
// 推荐顺序:从内到外
Cache cache = new LoggingCache( // 最外层:监控统计
new BlockingCache( // 防击穿保护
new SynchronizedCache( // 线程安全
new SerializedCache( // 序列化
new LruCache( // 淘汰策略
new PerpetualCache() // 基础存储
)))));
顺序设计原则
基础功能在内层:PerpetualCache作为存储核心
数据转换靠近核心:SerializedCache应在内层确保数据格式统一
并发控制在中层:SynchronizedCache/BlockingCache控制并发访问
监控统计在外层:LoggingCache最后包装以统计完整链路
五、生产环境中的装饰器实践
1. 性能敏感场景的优化
// 高并发读场景:使用读写锁替代同步锁
public class ReadWriteCache implements Cache {
private final Cache delegate;
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
@Override
public Object getObject(Object key) {
rwLock.readLock().lock();
try {
return delegate.getObject(key);
} finally {
rwLock.readLock().unlock();
}
}
}
2. 分布式缓存集成
// Redis缓存装饰器
public class RedisCache implements Cache {
private final JedisPool jedisPool;
private final String namespace;
@Override
public void putObject(Object key, Object value) {
try (Jedis jedis = jedisPool.getResource()) {
jedis.setex(buildRedisKey(key), expireTime, serialize(value));
}
}
}
3. 缓存预热策略
public class WarmUpCache implements Cache {
private final Cache delegate;
private final ScheduledExecutorService scheduler;
public void scheduleWarmUp() {
scheduler.scheduleAtFixedRate(this::warmUp, 0, 30, TimeUnit.MINUTES);
}
}
pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …