Mybatis缓存中装饰者模式的应用原理是怎样的?

2026-06-10 05:402阅读0评论SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计747个文字,预计阅读时间需要3分钟。

Mybatis缓存中装饰者模式的应用原理是怎样的?

@[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); }

Mybatis缓存中装饰者模式的应用原理是怎样的?

// 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; }
  • 先调用acquireLock()方法获取key对应的锁
  • 调用被装饰者的getObject()方法
  • 当获取到的值不为空的时候释放锁,为空就不释放锁了
  • 返回key对应的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); } } }
  • 创建CountDownLatch对象,key和CountDownLatch对象进行关联,ConcurrentHashMap用来保存key和CountDownLatch的关联
  • 如果CountDownLatch对象为空,说明ConcurrentHashMap没有key对应的CountDownLatch对象,就没有竞争,锁获取成功
  • 如果CountDownLatch对象不为空,说明发生了竞争,就阻塞当前线程,直到latch.countDown()方法来进行唤醒
  • 看下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(); }
  • 删除ConcurrentHashMap中key和CountDownLatch对象的关联
  • 唤醒等待的线程
  • 在真正使用的时候,线程之间产生竞争,线程a发现key没有关联的CountDownLatch对象,获取锁成功,获取锁成功后在ConcurrentHashMap集合中维护key和CountDownLatch对象的关联,线程b进入是没办法获取锁的,产生阻塞,这时候需要查询数据库的数据并调用putObject()方法来释放锁,从而线程b被唤醒

    总结

    本篇文章主要从装饰者模式的角度分析了一下缓存模块的被装饰器接口Cache和实现类PerpetualCache,PerpetualCache通过HasnMap来缓存数据,还介绍了一个装饰器BlockingCache,分析了它获取缓存的逻辑:先获取key对应的锁然后获取数据最后释放锁,CountDownLatch中保存key和CountDownLatch对象的关联来表示加锁是否成功

    本文共计747个文字,预计阅读时间需要3分钟。

    Mybatis缓存中装饰者模式的应用原理是怎样的?

    @[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); }

    Mybatis缓存中装饰者模式的应用原理是怎样的?

    // 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; }
  • 先调用acquireLock()方法获取key对应的锁
  • 调用被装饰者的getObject()方法
  • 当获取到的值不为空的时候释放锁,为空就不释放锁了
  • 返回key对应的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); } } }
  • 创建CountDownLatch对象,key和CountDownLatch对象进行关联,ConcurrentHashMap用来保存key和CountDownLatch的关联
  • 如果CountDownLatch对象为空,说明ConcurrentHashMap没有key对应的CountDownLatch对象,就没有竞争,锁获取成功
  • 如果CountDownLatch对象不为空,说明发生了竞争,就阻塞当前线程,直到latch.countDown()方法来进行唤醒
  • 看下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(); }
  • 删除ConcurrentHashMap中key和CountDownLatch对象的关联
  • 唤醒等待的线程
  • 在真正使用的时候,线程之间产生竞争,线程a发现key没有关联的CountDownLatch对象,获取锁成功,获取锁成功后在ConcurrentHashMap集合中维护key和CountDownLatch对象的关联,线程b进入是没办法获取锁的,产生阻塞,这时候需要查询数据库的数据并调用putObject()方法来释放锁,从而线程b被唤醒

    总结

    本篇文章主要从装饰者模式的角度分析了一下缓存模块的被装饰器接口Cache和实现类PerpetualCache,PerpetualCache通过HasnMap来缓存数据,还介绍了一个装饰器BlockingCache,分析了它获取缓存的逻辑:先获取key对应的锁然后获取数据最后释放锁,CountDownLatch中保存key和CountDownLatch对象的关联来表示加锁是否成功