手写MyBatis第78弹:装饰器模式在MyBatis二级缓存中的应用:从LRU到防击穿的全方案实现
MyBatis二级缓存装饰器模式深度解析:从LRU到防击穿的全方案实现
手写MyBatis缓存装饰器:SynchronizedCache与BlockingCache实战
装饰器模式在MyBatis缓存中的应用:灵活组合的架构设计
二级缓存高级特性:序列化、LRU淘汰、日志统计完整实现
MyBatis缓存装饰器链:如何设计可扩展的CacheBuilder
目录
正文
一、装饰器模式在缓存架构中的核心价值
装饰器模式 vs 继承的优劣对比
二、核心缓存装饰器实现详解
1. SynchronizedCache:线程安全的基础保障
2. LoggingCache:缓存命中率监控
3. SerializedCache:对象序列化与副本保护
4. LruCache:内存资源智能管理
5. BlockingCache:防止缓存击穿的保护盾
三、CacheBuilder:装饰器的灵活组合器
四、装饰器执行顺序的架构考量
正确的顺序设计
顺序设计原则
五、生产环境中的装饰器实践
1. 性能敏感场景的优化
2. 分布式缓存集成
3. 缓存预热策略
六、装饰器模式的架构思想延伸
七、总结
🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐是作者创作的最大动力🤞
💖📕🎉🔥 支持我:点赞👍+收藏⭐️+留言📝欢迎留言讨论
🔥🔥🔥(源码 + 调试运行 + 问题答疑)
🔥🔥🔥 有兴趣可以联系我。文末有免费源码
免费获取源码。
更多内容敬请期待。如有需要可以联系作者免费送
更多源码定制,项目修改,项目二开可以联系作者
点击可以进行搜索(每人免费送一套代码):千套源码目录(点我)2025元旦源码免费送(点我)
我们常常在当下感到时间慢,觉得未来遥远,但一旦回头看,时间已经悄然流逝。对于未来,尽管如此,也应该保持一种从容的态度,相信未来仍有许多可能性等待着我们。
正文
一、装饰器模式在缓存架构中的核心价值
装饰器模式(Decorator Pattern)是MyBatis二级缓存架构的精髓所在。它通过动态组合的方式,为缓存功能添加各种增强特性,而不需要修改原有的缓存实现。这种设计符合开闭原则,使得系统具有良好的扩展性和灵活性。
装饰器模式 vs 继承的优劣对比
-
继承的局限性:如果使用继承,要实现所有功能组合需要创建大量子类
-
装饰器的优势:通过组合方式,可以动态地、透明地添加功能
二、核心缓存装饰器实现详解
1. SynchronizedCache:线程安全的基础保障
public class SynchronizedCache implements Cache {private final Cache delegate;public SynchronizedCache(Cache delegate) {this.delegate = delegate;}@Overridepublic synchronized void putObject(Object key, Object value) {delegate.putObject(key, value);}@Overridepublic synchronized Object getObject(Object key) {return delegate.getObject(key);}@Overridepublic synchronized Object removeObject(Object key) {return delegate.removeObject(key);}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic void putObject(Object key, Object value) {if (value == null || value instanceof Serializable) {delegate.putObject(key, serialize((Serializable) value));} else {throw new CacheException("缓存对象必须实现Serializable接口");}}@Overridepublic 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<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) {@Overrideprotected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {boolean tooBig = size() > size;if (tooBig) {eldestKey = eldest.getKey();}return tooBig;}};}@Overridepublic void putObject(Object key, Object value) {delegate.putObject(key, value);cycleKeyList(key);}@Overridepublic 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:防止缓存击穿的保护盾
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<>();}@Overridepublic Object getObject(Object key) {acquireLock(key);try {return delegate.getObject(key);} finally {releaseLock(key);}}@Overridepublic 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();@Overridepublic 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;@Overridepublic 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);}}
六、装饰器模式的架构思想延伸
装饰器模式的价值不仅限于缓存实现,它体现了重要的软件设计原则:
-
单一职责原则:每个装饰器只关注一个特定功能
-
开闭原则:新增功能不需要修改现有代码
-
组合优于继承:通过组合实现功能的灵活扩展
这种设计思想可以应用到:
-
日志系统的Appender装饰
-
网络连接的Filter链
-
业务逻辑的Interceptor栈
七、总结
MyBatis二级缓存的装饰器体系展示了优秀架构设计的魅力。通过合理的装饰器组合,可以构建出功能强大、性能优越、可维护性高的缓存系统。
关键收获:
-
装饰器模式实现了功能的正交组合
-
SerializedCache解决了对象共享的核心问题
-
BlockingCache有效防止缓存击穿
-
CacheBuilder提供了优雅的配置方式
-
装饰器顺序影响系统行为和性能
在实际项目中,应根据具体场景选择合适的装饰器组合,并通过监控数据持续优化缓存策略。
🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐是作者创作的最大动力🤞
💖📕🎉🔥 支持我:点赞👍+收藏⭐️+留言📝欢迎留言讨论
🔥🔥🔥(源码 + 调试运行 + 问题答疑)
🔥🔥🔥 有兴趣可以联系我。文末有免费源码
💖学习知识需费心,
📕整理归纳更费神。
🎉源码免费人人喜,
🔥码农福利等你领!💖常来我家多看看,
📕网址:扣棣编程,
🎉感谢支持常陪伴,
🔥点赞关注别忘记!💖山高路远坑又深,
📕大军纵横任驰奔,
🎉谁敢横刀立马行?
🔥唯有点赞+关注成!
往期文章推荐:
基于Springboot + vue实现的学生宿舍信息管理系统
免费获取宠物商城源码--SpringBoot+Vue宠物商城网站系统
【2025小年源码免费送】