Mybatis的核心工作原理之SqlSession与Mapper
从宏观角度学习Mybatis的架构、工作原理、主要模块,从微观角度学习Mybatis的工作原理与设计思想。
一、SqlSession
每一次的操作数据库,都需要创建一个会话,我们用到openSession()方法来创建。接下来我们来看看SqlSession创建过程中都做了哪些步骤。
SqlSession sqlSession = factory.openSession();
通过前面对SqlSessionFactory源码的解析,我们知道这里是DefaultSqlSessionFactory的openSession()方法创建的。
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
首先获取默认的执行器类型configuration.getDefaultExecutorType(),默认是ExecutorType.SIMPLE。
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();
}
}
我们在前面解析标签的时候,创建了TransactionFactory事务工厂。
根据事务工厂和默认的执行器类型,创建执行器 。
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 {
// 默认 SimpleExecutor
executor = new SimpleExecutor(this, transaction);
}
// 二级缓存开关,settings 中的 cacheEnabled 默认是 true
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
// 植入插件的逻辑,至此,四大对象已经全部拦截完毕
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
最后返回一个DefaultSqlSession对象。
return new DefaultSqlSession(configuration, executor, autoCommit);
一、Mapper
我们再来看下通过getMapper()方法获取对应接口的对象的实现原理。
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
进入DefaultSqlSession的getMapper()方法查看。
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// mapperRegistry中注册的有Mapper的相关信息 在解析映射文件时 调用过addMapper方法
return mapperRegistry.getMapper(type, sqlSession);
}
mapperRegistry中注册的有Mapper的相关信息,继续进入mapperRegistry.getMapper()方法:
/**
* 获取Mapper接口对应的代理对象
*/
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// 获取Mapper接口对应的 MapperProxyFactory 对象
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
进入newInstance()方法:
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
继续j进入:
/**
* 创建实现了 mapperInterface 接口的代理对象
*/
protected T newInstance(MapperProxy<T> mapperProxy) {
// 1:类加载器:2:被代理类实现的接口、3:实现了 InvocationHandler 的触发管理类
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
最终我们发现代理对象是通过JDK动态代理创建的返回的,里面也传递了一个实现了InvocationHandler接口的类。
public class MapperProxy<T> implements InvocationHandler, Serializable
最终会调用到MapperProxy类的invoke()方法。具体分析在Mybatis的核心工作原理之SQL执行中讲解。