Mybatis缓存中装饰者模式的应用原理是怎样的?
- 内容介绍
- 文章标签
- 相关推荐
本文共计747个文字,预计阅读时间需要3分钟。
@[TOC]聊聊Mybatis的缓存装饰者模式装饰者模式是一种结构型设计模式,它允许向现有对象添加新的功能,同时又不改变其接口。在Mybatis中,缓存装饰者模式被用于扩展和增强缓存的特性。
装饰器的Component使用在Mybatis中,装饰器模式通过一个抽象的`Cache`接口实现。以下是一个简化的`Cache`接口定义:
javapublic interface Cache { String getId(); void putObject(Object key, Object value); Object getObject(Object key); Object removeObject(Object key);}
Cache接口实现Mybatis提供了多种缓存实现,如`PerpetualCache`和`FIFOCache`。以下是`PerpetualCache`的一个简单示例:
javapublic class PerpetualCache implements Cache { private final String id; private final Map cache=new HashMap();
public PerpetualCache(final String id) { this.id=id; }
@Override public String getId() { return this.id; }
@Override public void putObject(Object key, Object value) { cache.put(key, value); }
@Override public Object getObject(Object key) { return cache.get(key); }
@Override public Object removeObject(Object key) { return cache.remove(key); }
// Additional methods and overrides for cache management}
@[TOC]
聊聊Mybatis的缓存之装饰者模式
装饰器的Component被装饰者
Cache接口:
public interface Cache { String getId(); void putObject(Object key, Object value); Object getObject(Object key); Object removeObject(Object key); void clear(); int getSize(); default ReadWriteLock getReadWriteLock() { return null; } }PerpetualCache实现了这个接口,使用HashMap来缓存数据
Cache是装饰器模式的Component接口,PerpetualCache是接口的实现类
装饰器模式的装饰者
BlockingCache实现了Cache接口,具有阻塞线程的功能,看一下它的获取缓存数据的方法:
@Override public Object getObject(Object key) { acquireLock(key); Object value = delegate.getObject(key); if (value != null) { releaseLock(key); } return value; }获取锁BlockingCache的acquireLock()方法:
private final ConcurrentHashMap<Object, CountDownLatch> locks; private void acquireLock(Object key) { CountDownLatch newLatch = new CountDownLatch(1); while (true) { CountDownLatch latch = locks.putIfAbsent(key, newLatch); if (latch == null) { break; } try { if (timeout > 0) { boolean acquired = latch.await(timeout, TimeUnit.MILLISECONDS); if (!acquired) { throw new CacheException( "Couldn't get a lock in " + timeout + " for the key " + key + " at the cache " + delegate.getId()); } } else { latch.await(); } } catch (InterruptedException e) { throw new CacheException("Got interrupted while trying to acquire lock for key " + key, e); } } }看下releaseLock()方法:
private void releaseLock(Object key) { CountDownLatch latch = locks.remove(key); if (latch == null) { throw new IllegalStateException("Detected an attempt at releasing unacquired lock. This should never happen."); } latch.countDown(); }在真正使用的时候,线程之间产生竞争,线程a发现key没有关联的CountDownLatch对象,获取锁成功,获取锁成功后在ConcurrentHashMap集合中维护key和CountDownLatch对象的关联,线程b进入是没办法获取锁的,产生阻塞,这时候需要查询数据库的数据并调用putObject()方法来释放锁,从而线程b被唤醒
总结
本篇文章主要从装饰者模式的角度分析了一下缓存模块的被装饰器接口Cache和实现类PerpetualCache,PerpetualCache通过HasnMap来缓存数据,还介绍了一个装饰器BlockingCache,分析了它获取缓存的逻辑:先获取key对应的锁然后获取数据最后释放锁,CountDownLatch中保存key和CountDownLatch对象的关联来表示加锁是否成功
本文共计747个文字,预计阅读时间需要3分钟。
@[TOC]聊聊Mybatis的缓存装饰者模式装饰者模式是一种结构型设计模式,它允许向现有对象添加新的功能,同时又不改变其接口。在Mybatis中,缓存装饰者模式被用于扩展和增强缓存的特性。
装饰器的Component使用在Mybatis中,装饰器模式通过一个抽象的`Cache`接口实现。以下是一个简化的`Cache`接口定义:
javapublic interface Cache { String getId(); void putObject(Object key, Object value); Object getObject(Object key); Object removeObject(Object key);}
Cache接口实现Mybatis提供了多种缓存实现,如`PerpetualCache`和`FIFOCache`。以下是`PerpetualCache`的一个简单示例:
javapublic class PerpetualCache implements Cache { private final String id; private final Map cache=new HashMap();
public PerpetualCache(final String id) { this.id=id; }
@Override public String getId() { return this.id; }
@Override public void putObject(Object key, Object value) { cache.put(key, value); }
@Override public Object getObject(Object key) { return cache.get(key); }
@Override public Object removeObject(Object key) { return cache.remove(key); }
// Additional methods and overrides for cache management}
@[TOC]
聊聊Mybatis的缓存之装饰者模式
装饰器的Component被装饰者
Cache接口:
public interface Cache { String getId(); void putObject(Object key, Object value); Object getObject(Object key); Object removeObject(Object key); void clear(); int getSize(); default ReadWriteLock getReadWriteLock() { return null; } }PerpetualCache实现了这个接口,使用HashMap来缓存数据
Cache是装饰器模式的Component接口,PerpetualCache是接口的实现类
装饰器模式的装饰者
BlockingCache实现了Cache接口,具有阻塞线程的功能,看一下它的获取缓存数据的方法:
@Override public Object getObject(Object key) { acquireLock(key); Object value = delegate.getObject(key); if (value != null) { releaseLock(key); } return value; }获取锁BlockingCache的acquireLock()方法:
private final ConcurrentHashMap<Object, CountDownLatch> locks; private void acquireLock(Object key) { CountDownLatch newLatch = new CountDownLatch(1); while (true) { CountDownLatch latch = locks.putIfAbsent(key, newLatch); if (latch == null) { break; } try { if (timeout > 0) { boolean acquired = latch.await(timeout, TimeUnit.MILLISECONDS); if (!acquired) { throw new CacheException( "Couldn't get a lock in " + timeout + " for the key " + key + " at the cache " + delegate.getId()); } } else { latch.await(); } } catch (InterruptedException e) { throw new CacheException("Got interrupted while trying to acquire lock for key " + key, e); } } }看下releaseLock()方法:
private void releaseLock(Object key) { CountDownLatch latch = locks.remove(key); if (latch == null) { throw new IllegalStateException("Detected an attempt at releasing unacquired lock. This should never happen."); } latch.countDown(); }在真正使用的时候,线程之间产生竞争,线程a发现key没有关联的CountDownLatch对象,获取锁成功,获取锁成功后在ConcurrentHashMap集合中维护key和CountDownLatch对象的关联,线程b进入是没办法获取锁的,产生阻塞,这时候需要查询数据库的数据并调用putObject()方法来释放锁,从而线程b被唤醒
总结
本篇文章主要从装饰者模式的角度分析了一下缓存模块的被装饰器接口Cache和实现类PerpetualCache,PerpetualCache通过HasnMap来缓存数据,还介绍了一个装饰器BlockingCache,分析了它获取缓存的逻辑:先获取key对应的锁然后获取数据最后释放锁,CountDownLatch中保存key和CountDownLatch对象的关联来表示加锁是否成功

