MyBatis中关于Cache和CachingExecutor接口的实现类也使用了装饰者设计模式。Executor是MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护;CachingExecutor是一个Executor的装饰器,给一个Executor增加了缓存的功能。此时可以看做是对Executor类的一个增强,故使用装饰器模式是合适的。
Executor
首先我们看下Executor,打开MyBatis的源码org.apache.ibatis.session.Configuration
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
//如果开启了二级缓存则装饰原先的Executor
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
CachingExecutor (装饰器的具体实现对象)
public class CachingExecutor implements Executor {
//持有组件对象
private Executor delegate;
private TransactionalCacheManager tcm = new TransactionalCacheManager();
//构造方法,传入组件对象
public CachingExecutor(Executor delegate) {
this.delegate = delegate;
delegate.setExecutorWrapper(this);
}
@Override
public int update(MappedStatement ms, Object parameterObject) throws SQLException {
//转发请求给组件对象,可以在转发前后执行一些附加动作
flushCacheIfRequired(ms);
return delegate.update(ms, parameterObject);
}
//...
}
当然,这个装饰器模式的使用与标准的有点差异,但是完成的功能性质相同。
Cache
在MyBatis中有一级和二级缓存。在BaseExecutor(SimpleExecutor\BatchExecutor的父类)中,存放着一级缓存,org.apache.ibatis.cache.impl.PerpetualCache 是默认缓存的实现。
而当我们初始化时,会对PerpetualCache进行包装
查看org.apache.ibatis.mapping.CacheBuilder中源码,我们开启二级缓存后会包装多层,比如加上LruCache来进行缓存的清除等。
public Cache build() {
setDefaultImplementations();
Cache cache = newBaseCacheInstance(implementation, id);
setCacheProperties(cache);
// issue #352, do not apply decorators to custom caches
//加上一些装饰
if (PerpetualCache.class.equals(cache.getClass())) {
for (Class<? extends Cache> decorator : decorators) {
cache = newCacheDecoratorInstance(decorator, cache);
setCacheProperties(cache);
}
cache = setStandardDecorators(cache);
} else if (!LoggingCache.class.isAssignableFrom(cache.getClass())) {
cache = new LoggingCache(cache);
}
return cache;
}
MyBastis中的装饰器实现对象
包装完成之后呢,在查询等方法进行缓存操作的时候,就拥有了更强大的功能了。
具体使用
好了,说了这么多,我们看下它是如何使用装饰器模式的吧
Cache 组件对象的接口
PerpetualCache 具体组件,是我们需要装饰的对象
LruCache等 是具体装饰类,被装饰的对象