在Mybatis中有三种executor:
- SimpleExecutor – SIMPLE 就是普通的执行器
- ReuseExecutor -执行器会重用预处理语句(prepared statements)
BatchExecutor –它是批量操作的执行器
在mybatis-config.xml里配置如下:
<setting name="defaultExecutorType" value="SIMPLE"/>
value的只可选:SIMPLE、REUSE和BATCH。默认为SIMPLE。
当Mybatis整合Spring后,Spring扫描后生成的Mapper对象,底层使用的SqlSession都是用的默认的Executor,即SimpleExecutor。这个时候,想要使用非默认的Executor,可以这么配置它:
<bean id="sqlSessionTemplateBatch" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
<!--更新采用批量的executor -->
<constructor-arg index="1" value="BATCH"/>
</bean>
这样,它便是一个批量的执行器。mybatis的三个executor都有一个共同的父类——BaseExecutor。
Executor的初始化:
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) {
executor = new CachingExecutor(executor);
}
//采用责任链模式,来产生代理对象
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
pluginAll的代码如下:
public Object pluginAll(Object target) {
//遍历mybatis的拦截器
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);//生成代理对象
}
return target;
}
由上可知,任何一个插件(Interceptor)都有机会拦截这个真实的服务对象(executor),这便是责任链模式,所以完全可以提供一个插件(Interceptor),进入到代理对象的invoke方法里面,来改变executor的行为和方法。但是,得注意,插件会改变Mybatis的底层代码,所以要谨慎使用插件。
mybatis为我们提供了Plugin.java类来实现我们所需要的动态的代理功能,代码如下:
public class Plugin implements InvocationHandler {
private Object target;
private Interceptor interceptor;
private Map<Class<?>, Set<Method>> signatureMap;
private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) {
this.target = target;
this.interceptor = interceptor;
this.signatureMap = signatureMap;
}
//通过这个方法生成代理对象
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;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
Set<Method> methods = signatureMap.get(method.getDeclaringClass());
if (methods != null && methods.contains(method)) {
return interceptor.intercept(new Invocation(target, method, args));
}
return method.invoke(target, args);
} catch (Exception e) {
throw ExceptionUtil.unwrapThrowable(e);
}
}
......
}
Executor开始执行:
首先它先生成StatementHandler对象。
通过prepareStatement方法调用prepare方法初始化参数。
然后使用parameterize方法设置参数到运行环境。
然后便通过handler.query(stmt, resultHandler);方法来完成结果组装。
于是我们的焦点就集中在了StatementHandler对象上,下章我们将谈及它。