MyBatis二级缓存装饰器模式深度解析:从LRU到防击穿的全方案实现
手写MyBatis缓存装饰器:SynchronizedCache与BlockingCache实战
装饰器模式在MyBatis缓存中的应用:灵活组合的架构设计
二级缓存高级特性:序列化、LRU淘汰、日志统计完整实现
MyBatis缓存装饰器链:如何设计可扩展的CacheBuilder
目录
[装饰器模式 vs 继承的优劣对比](#装饰器模式 vs 继承的优劣对比)
[1. SynchronizedCache:线程安全的基础保障](#1. SynchronizedCache:线程安全的基础保障)
[2. LoggingCache:缓存命中率监控](#2. LoggingCache:缓存命中率监控)
[3. SerializedCache:对象序列化与副本保护](#3. SerializedCache:对象序列化与副本保护)
[4. LruCache:内存资源智能管理](#4. LruCache:内存资源智能管理)
[5. BlockingCache:防止缓存击穿的保护盾](#5. BlockingCache:防止缓存击穿的保护盾)
[1. 性能敏感场景的优化](#1. 性能敏感场景的优化)
[2. 分布式缓存集成](#2. 分布式缓存集成)
[3. 缓存预热策略](#3. 缓存预热策略)
🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐是作者创作的最大动力🤞
💖📕🎉🔥 支持我:点赞👍+收藏⭐️+留言📝欢迎留言讨论
🔥🔥🔥(源码 + 调试运行 + 问题答疑)
🔥🔥🔥 有兴趣可以联系我。文末有免费源码
免费获取源码。
更多内容敬请期待。如有需要可以联系作者免费送
更多源码定制,项目修改,项目二开可以联系作者
点击可以进行搜索(每人免费送一套代码):千套源码目录(点我)
2025元旦源码免费送(点我)
我们常常在当下感到时间慢,觉得未来遥远,但一旦回头看,时间已经悄然流逝。对于未来,尽管如此,也应该保持一种从容的态度,相信未来仍有许多可能性等待着我们。
正文
一、装饰器模式在缓存架构中的核心价值
装饰器模式(Decorator Pattern)是MyBatis二级缓存架构的精髓所在。它通过动态组合的方式,为缓存功能添加各种增强特性,而不需要修改原有的缓存实现。这种设计符合开闭原则,使得系统具有良好的扩展性和灵活性。
装饰器模式 vs 继承的优劣对比
-
继承的局限性:如果使用继承,要实现所有功能组合需要创建大量子类
-
装饰器的优势:通过组合方式,可以动态地、透明地添加功能
二、核心缓存装饰器实现详解
1. SynchronizedCache:线程安全的基础保障
java
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:缓存命中率监控
java
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:对象序列化与副本保护
这是二级缓存中最关键的装饰器,解决对象共享的核心问题:
java
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:内存资源智能管理
java
public class LruCache implements Cache {
private final Cache delegate;
private final LinkedHashMap<Object, Object> keyMap;
private Object eldestKey;
public LruCache(Cache delegate, final int size) {
this.delegate = delegate;
this.keyMap = new LinkedHashMap<Object, Object>(size, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {
boolean tooBig = size() > size;
if (tooBig) {
eldestKey = eldest.getKey();
}
return tooBig;
}
};
}
@Override
public void putObject(Object key, Object value) {
delegate.putObject(key, value);
cycleKeyList(key);
}
@Override
public Object getObject(Object key) {
keyMap.get(key); // 触发访问顺序更新
return delegate.getObject(key);
}
private void cycleKeyList(Object key) {
keyMap.put(key, key);
if (eldestKey != null) {
delegate.removeObject(eldestKey);
eldestKey = null;
}
}
}
LRU算法精髓:通过LinkedHashMap的访问顺序特性,自动维护最近使用顺序。
5. BlockingCache:防止缓存击穿的保护盾
java
public class BlockingCache implements Cache {
private final Cache delegate;
private final ConcurrentHashMap<Object, ReentrantLock> 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:装饰器的灵活组合器
java
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();
建造者模式优势:通过链式调用,直观地组合各种缓存特性。
四、装饰器执行顺序的架构考量
装饰器的包装顺序直接影响缓存行为:
正确的顺序设计
java
// 推荐顺序:从内到外
Cache cache = new LoggingCache( // 最外层:监控统计
new BlockingCache( // 防击穿保护
new SynchronizedCache( // 线程安全
new SerializedCache( // 序列化
new LruCache( // 淘汰策略
new PerpetualCache() // 基础存储
)))));
顺序设计原则
-
基础功能在内层:PerpetualCache作为存储核心
-
数据转换靠近核心:SerializedCache应在内层确保数据格式统一
-
并发控制在中层:SynchronizedCache/BlockingCache控制并发访问
-
监控统计在外层:LoggingCache最后包装以统计完整链路
五、生产环境中的装饰器实践
1. 性能敏感场景的优化
java
// 高并发读场景:使用读写锁替代同步锁
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. 分布式缓存集成
java
// 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. 缓存预热策略
java
public class WarmUpCache implements Cache {
private final Cache delegate;
private final ScheduledExecutorService scheduler;
public void scheduleWarmUp() {
scheduler.scheduleAtFixedRate(this::warmUp, 0, 30, TimeUnit.MINUTES);
}
}
六、装饰器模式的架构思想延伸
装饰器模式的价值不仅限于缓存实现,它体现了重要的软件设计原则:
-
单一职责原则:每个装饰器只关注一个特定功能
-
开闭原则:新增功能不需要修改现有代码
-
组合优于继承:通过组合实现功能的灵活扩展
这种设计思想可以应用到:
-
日志系统的Appender装饰
-
网络连接的Filter链
-
业务逻辑的Interceptor栈
七、总结
MyBatis二级缓存的装饰器体系展示了优秀架构设计的魅力。通过合理的装饰器组合,可以构建出功能强大、性能优越、可维护性高的缓存系统。
关键收获:
-
装饰器模式实现了功能的正交组合
-
SerializedCache解决了对象共享的核心问题
-
BlockingCache有效防止缓存击穿
-
CacheBuilder提供了优雅的配置方式
-
装饰器顺序影响系统行为和性能
在实际项目中,应根据具体场景选择合适的装饰器组合,并通过监控数据持续优化缓存策略。

🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐是作者创作的最大动力🤞
💖📕🎉🔥 支持我:点赞👍+收藏⭐️+留言📝欢迎留言讨论
🔥🔥🔥(源码 + 调试运行 + 问题答疑)
🔥🔥🔥 有兴趣可以联系我。文末有免费源码
💖学习知识需费心,
📕整理归纳更费神。
🎉源码免费人人喜,
🔥码农福利等你领!💖常来我家多看看,
📕网址:扣棣编程** ,
🎉感谢支持常陪伴,
🔥点赞关注别忘记!**💖山高路远坑又深,
📕大军纵横任驰奔,
🎉谁敢横刀立马行?
🔥唯有点赞+关注成!
往期文章推荐:
基于Springboot + vue实现的学生宿舍信息管理系统
免费获取宠物商城源码--SpringBoot+Vue宠物商城网站系统
【2025小年源码免费送】