一 MapperFactoryBean
1.1 MapperFactoryBean
- spring容器中管理的dao接口bean是MapperFactoryBean
- MapperFactoryBean.getObject()的实现是调用
this.getSqlSession()
获取的DefaultSqlSession的方法getMapper(this.mapperInterface);
- DefaultSqlSession中调用的是mybatis配置的getMapper(type, this)`方法
- mybatis配置中调用的是mapperRegistry的
getMapper(type, sqlSession)
方法
1.2 MapperRegistry
- spring扫描dao接口包时,添加接口对应的代理工厂类,MapperRegistry中
Map<Class<?>/*dao接口*/, MapperProxyFactory<?>> knownMappers
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) {
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
knownMappers.put(type, new MapperProxyFactory<T>(type));
// It's important that the type is added before the parser is run
// otherwise the binding may automatically be attempted by the
// mapper parser. If the type is already known, it won't try.
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
1.3 MapperProxy
- 获取时使用工厂类新建实例
mapperProxyFactory.newInstance(sqlSession)
,即以MapperProxy为代理函数的代理类
Proxy.newProxyInstance(mapperInterface.getClassLoader(),
new Class[] { mapperInterface },
new MapperProxy<T>(sqlSession, mapperInterface, methodCache));
- MapperProxy使用MapperMethod代理底层不同dao接口,进行接口参数转换和返回值转换,并调用sqlsession代理接口
1.4 MapperMethod
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new SqlCommand(config, mapperInterface, method);
this.method = new MethodSignature(config, method);
}
1.4.1 SqlCommand
- 函数对应sql指令名为接口名.方法名
- 从mybatis配置中获取映射文件解析的sql指令对应的MappedStatement
- 存储sql指令名称和类型
name = ms.getId();
type = ms.getSqlCommandType();
1.4.2 MethodSignature
二 SqlSession
2.1 SqlSessionTemplate
- SqlSession工厂代理,线程局部变量保存,线程安全。支持事务sqlSession的线程内共享。
- 代理DefaultSqlSession的接口
2.2 DefaultSqlSession
2.2.1 初始化
- 初始化或获取线程共享事务
- 根据执行器类型新建sql命令执行器
- 实例化DefaultSqlSession
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
2.2.2 方法
- select*方法调用executor.query()
- insert,update,delete调用executor.update()
- commit,rollback,flush调用executor的对应函数
三 executor
3.1 初始化
- 根据类型创建executor,并增加执行器插件代理。默认是SIMPLE类型。
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;
}
3.2 SimpleExecutor
3.2.1 doUpdate处理流程
- 初始化RoutingStatementHandler,添加对应的指令插件
-
Statement stmt = handler.prepare(connection);
Statement预处理
-
handler.parameterize(stmt);
参数设置
-
handler.update(stmt);
执行更新
3.2.2 doQuery处理流程
- 初始化RoutingStatementHandler,添加对应的指令插件
-
Statement stmt = handler.prepare(connection);
Statement预处理
-
handler.parameterize(stmt);
参数设置
-
handler.<E>query(stmt, resultHandler);;
执行查询,resultHandler进行返回结果处理
3.3 ReuseExecutor
- doUpdate,doQuery处理流程与SimpleExecutor相同
- 区别是提供了
Map<String, Statement> statementMap
。以sql命令为key对Statement stmt
的缓存
-
doFlushStatements()
统一清除缓存,关闭Statement
3.4 BatchExecutor
3.5 BaseExecutor
- 所有executor继承自BaseExecutor
- update调用子类doUpdate之前,先清除本地缓存
3.5.1 query
- 查询时执行一级缓存,SqlSession内共享,对事务性查询是线程内共享SqlSession,也就是共享一级缓存数据。
- 先判断flushCache配置,为true,则先清空缓存,默认为false
- 查询缓存以key存储,
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql)
- 存在缓存,则不再执行sql查询。缓存参数
localOutputParameterCache
转换后返回handleLocallyCachedOutputParameters()
-
deferredLoads
延迟加载处理
-
configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT
语句级范围则请求完成后清除缓存,session范围缓存则可用。
3.6 CachingExecutor
- SqlSession存储的执行器实际是CachingExecutor,内部代理了SimpleExecutor.
- CachingExecutor实现了mybatis的二级缓存功能,缓存数据存储在MappedStatement中,
Cache cache = ms.getCache();
- MappedStatement是多个SqlSession共享的,即二级缓存是共享实用的。
- 查询时,若配置使用二级缓存则先取缓存中数据
四 插件
- 在mybatis配置中使用
InterceptorChain interceptorChain
保存所有插件配置
4.1 InterceptorChain
- 使用
List<Interceptor> interceptors
存储所有插件
- 调用插件方法
target = interceptor.plugin(target);
,对目标类创建插件代理,一般内部实现使用org.apache.ibatis.plugin.Plugin
创建代理。
4.2 Plugin
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;
}
- 拦截方法内,则调用插件的
intercept
方法,执行插件处理。
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);
4.3 插件类型
- 插件分为Executor执行器插件,ParameterHandler参数处理插件,ResultSetHandler结果处理插件,StatementHandler预处理插件。
-
interceptor.plugin(target)
创建插件代理时,需要判断target
是否是期望的插件目标点
- ParameterHandler参数处理插件
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}
ResultHandler resultHandler, BoundSql boundSql) {
ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
return resultSetHandler;
}
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
- Executor执行器插件,在根据执行器类型
newExecutor
新建执行器时,创建executor = (Executor) interceptorChain.pluginAll(executor);