private Executor delegate; private TransactionalCacheManager tcm = new TransactionalCacheManager(); public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { Cache cache = ms.getCache(); .... List<E> list = (List<E>) tcm.getObject(cache, key); if (list == null) { list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); tcm.putObject(cache, key, list); // issue #578 and #116 } return list; } } return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
其中TransactionalCacheManager
属性为二级缓存提供了事务能力。
public void commit(boolean required) throws SQLException { delegate.commit(required); tcm.commit();也就是事务提交时才会将数据放入到二级缓存中去 }
总结下二级缓存
- 二级缓存是层层装饰
- 二级缓存工作原理是装饰普通执行器
- 装饰执行器使用
TransactionalCacheManager
为二级缓存提供事务能力
六、插件
一句话总结mybaits插件:代理,代理,代理,还是代理。
Mybatis的插件原理也是动态代理技术。
public Executor newExecutor(Transaction transaction, ExecutorType executorType) { .. executor = new SimpleExecutor(this, transaction); .... if (cacheEnabled) { executor = new CachingExecutor(executor); } 插件的入口 executor = (Executor) interceptorChain.pluginAll(executor); return executor; } InterceptorChain public Object pluginAll(Object target) { for (Interceptor interceptor : interceptors) { target = interceptor.plugin(target); } return target; }
以分页插件为例,
创建完Executor后,会执行插件的plugn
方法,插件的plugn
会调用Plugin.wrap
方法,在此方法中我们看到了我们属性的JDK动态代理技术。创建Executor
的代理类,以Plugin为增强。
QueryInterceptor public Object plugin(Object target) { return Plugin.wrap(target, this); } public class Plugin implements InvocationHandler { public static Object wrap(Object target, Interceptor interceptor) { Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor); Class<?> type = target.getClass(); Class<?>[] interfaces = getAllInterfaces(type, signatureMap); if (interfaces.length > 0) { return Proxy.newProxyInstance( type.getClassLoader(), interfaces, new Plugin(target, interceptor, signatureMap)); } return target; } }
最终的执行链:Executor代理类方法--》Plugin.invoke方法--》插件.intercept方法--》Executor类方法
七、结果映射
介于结果映射比较复杂,再开一篇来细节吧
八、总结
- mybatis可以说将装饰器模式,动态代理用到了极致。非常值得我们学习。
- 框架留给应用者的应该是框架运行的基本单位,也就是域值的概念,应用者只需要定义原料,然后就是黑盒运行。
例如:
- Spring的
BeanDefinition
- Mybatis的
MappedStatement
Mybatis是一个非常值得阅读的框架,相比于Spring的重,将Mybatis作为第一个源码学习的框架,非常非常的合适。