最近在阅读Mybatis源码,一步步边调试边阅读时发现,执行器executor调用query方法时,一会执行CachingExecutor里的query,一会执行BaseExecutor里的query,被绕晕了,于是准备梳理一下他们的联系。
一、
首先需要明确:BaseExecutor、CachingExecutor均为接口Executor的实现类,SimpleExecutor是BaseExecutor的子类。
二、
然后再看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);
}
if (cacheEnabled) {
//判断是否启用缓存(对应xml中的配置),如果启用,重新封装成缓存执行器
//装饰器设计模式,允许向一个现有的对象添加新的功能,同时又不改变其结构
executor = new CachingExecutor(executor);
}
//责任链设计模式,按照xml中配置的拦截器(可能有多个),依次对执行器设置
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
创建执行器对象一共分为三步:
第一步:根据指定的执行器类型,生成一个批量执行器BatchExecutor或复用执行器ReuseExecutor或简单执行器SimpleExecutor(三者是并列关系,本文以简单执行器SimpleExecutor为例)
第二步:根据xml中设置的是否开启二级缓存,决定是否将第一步获得的执行器进一步包装为缓存执行器CachingExecutor(装饰器设计模式,本文假设开启二级缓存)
<settings>
<!--开启二级缓存-->
<setting name="cacheEnabled" value="ture"/>
</settings>
包装时调用 CachingExecutor的构造方法,第一步中获得的执行器成为CachingExecutor的成员变量。