本文是结合spring boot使用mybatis源码来解析mybatis源码,使用mybatis-spring-boot-starter.1.3.0、spring-boot-2.1.6.RELEASE
我们大致分为两篇来介绍。
第一篇介绍解析mapper xml文件,实例化相关bean;
第二篇介绍mapper执行调用。
目录
-
- 1. 使用示例
- 2. 源码解析
-
-
- 1. MapperProxy
- 初始化MapperMethod
-
- 1. MapperMethod
- 2. SqlCommand(构建sql命令信息)
- 3. MethodSignature(解析方法对应的相关信息:入参,出参)
- 执行MapperMethod
-
- 1. MapperMethod
- 2. SqlSessionTemplate
- 3. SqlSessionTemplate$SqlSessionInterceptor
- openSqlSession
-
- 1. SqlSessionUtils(mybatis-spring-*.jar)
- 2. 创建SqlSession(DefaultSqlsessionFactory)
- 3. 创建Executor(configuration)(Executor缓存机制,缓存机制暂时先不详细说明)
- 4. 拦截器链:InterceptorChain(插件机制,可以另外详细了解,此处点到为止。可以分析Plugin类,注册插件)
- 执行SqlSession
-
- 1. DefaultSqlSession
- 2. 执行Executor(跟踪到SimpleExecutor继承了BaseExecutor)
-
- 3. 总结
1. 使用示例
结合上一篇的示例一起。
- TestService
上文我们介绍了实例化Mapper(MapperProxy),把这个Mapper注入到相关的@Autowired注解的字段上。也就是把MapperProxy注入到上面的orderMapper中@Component public class TestService { @Autowired private OrderMapper orderMapper; @PostConstruct public void test() { orderMapper.createOrder(new Order()); } }
2. 源码解析
MapperProxy是一个代理类。所以调试,直接跳入MapperProxy.invoke方法。
1. MapperProxy
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
//从缓存中获取MapperMethod,缓存中没有就创建,我们看看
final MapperMethod mapperMethod = cachedMapperMethod(method);
//执行MapperMethod
return mapperMethod.execute(sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
//从缓存中获取MapperMethod
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
// 缓存中没有就创建,把configuration传进去
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
初始化MapperMethod
1. MapperMethod
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
//创建SqlCommand、MethodSignature继续看看
this.command = new SqlCommand(config, mapperInterface, method);
this.method = new MethodSignature(config, mapperInterface, method);
}
2. SqlCommand(构建sql命令信息)
public static class SqlCommand {
//构建sqlCommand主要是为了填充这两个属性
private final String name; //全路径名称
private final SqlCommandType type; //insert/update等sql命令类型
public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
//解析 MappedStatement ,我们看看此处,内部方法
MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
configuration);
//...
}
private MappedStatement resolveMappedStatement(Class<?> mapperInterface, String methodName,
Class<?> declaringClass, Configuration configuration) {
//拼接当前statementId
String statementId = mapperInterface.getName() + "." + methodName;
//从configuration获取之前加载解析的MappedStatement(第一篇讲过)
if (configuration.hasStatement(statementId)) {
return configuration.getMappedStatement(statementId);
}
//...
return null;
}
}
3. MethodSignature(解析方法对应的相关信息:入参,出参)
public static class MethodSignature {
//返回是否数组、map、void、cursor
private final boolean returnsMany;
private final boolean returnsMap;
private final boolean returnsVoid;
private final boolean returnsCursor;
//返回类型
private final Class<?> returnType;
private final String mapKey;
private final Integer resultHandlerIndex;
//分页情况rowBounds
private final Integer rowBoundsIndex;
//参数情况(里边包含SortedMap,表示参数信息<参数顺序,参数名称>,并解析@Param注解信息)
private final ParamNameResolver paramNameResolver;
}
执行MapperMethod
1. MapperMethod
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
//根据类型执行
switch (command.getType()) {
case INSERT: {
//根据之前在MethodSignature.ParamNameResolver.SortedMap中保存的参数的顺序,获取相关参数的类型
Object param = method.convertArgsToSqlCommandParam(args);
//我们分析一下sqlSession.insert。此处的sqlsession就是我们上一篇说到的SqlSessionTemplate
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}
2. SqlSessionTemplate
//我们上一篇知道此处是创建了一个SqlSessionInterceptor拦截的DefaultSqlsession,所以会先执行SqlSessionInterceptor.invoke方法
private final SqlSession sqlSessionProxy;
@Override
public int insert(String statement, Object parameter) {
return this.sqlSessionProxy.insert(statement, parameter);
}
3. SqlSessionTemplate$SqlSessionInterceptor
private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//openSession。获取DefaultSqlSession
SqlSession sqlSession = getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator);
try {
//执行DefaultSqlSession方法,我们进去看看
Object result = method.invoke(sqlSession, args);
//如果没有事务(spring管理事务),则强制提交
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
sqlSession.commit(true);
}
return result;
} catch (Throwable t) {
throw unwrapped;
} finally {
if (sqlSession != null) {
//关闭sqlSession,或者释放SqlSession
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
}
}
openSqlSession
1. SqlSessionUtils(mybatis-spring-*.jar)
/**
* 从spring事务管理器中获取sqlsession,如果没有,就创建sqlsession,把sqlsession注册进去(主要是用spring管理事务要用,提交或回滚时,sqlSession提交或回滚自己内部的一些缓存)
**/
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
SqlSession session = sessionHolder(executorType, holder);
if (session != null) {
return session;
}
//openSession。我们进去追踪DefaultSqlsessionFactory.openSession ->DefaultSqlsessionFactory.openSessionFromDataSource
session = sessionFactory.openSession(executorType);
registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
return session;
}
2. 创建SqlSession(DefaultSqlsessionFactory)
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//前面讲到SqlSessionFactoryBean创建了这些环境、事务
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//通过事务管理器创建Transaction
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//创建Executor
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();
}
}
3. 创建Executor(configuration)(Executor缓存机制,缓存机制暂时先不详细说明)
protected boolean cacheEnabled = true;
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
//不同的ExecutorType创建不同的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);
}
//默认开启Executor缓存
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
//拦截器执行,这是一个拓展点,我们可以看看
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
4. 拦截器链:InterceptorChain(插件机制,可以另外详细了解,此处点到为止。可以分析Plugin类,注册插件)
public class InterceptorChain {
//Interceptor拦截器,mybatis的插件机制就是实现该接口
private final List<Interceptor> interceptors = new ArrayList<Interceptor>();
//执行拦截器,我们可以看到调用该方法的有四个地方
/**
* Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
* ParameterHandler (getParameterObject, setParameters)
* ResultSetHandler (handleResultSets, handleOutputParameters)
* StatementHandler (prepare, parameterize, batch, update, query)
**/
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
//添加拦截器
public void addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
}
public List<Interceptor> getInterceptors() {
return Collections.unmodifiableList(interceptors);
}
}
执行SqlSession
1. DefaultSqlSession
// //方法名称, 参数
@Override
public int insert(String statement, Object parameter) {
return update(statement, parameter);
}
@Override
public int update(String statement, Object parameter) {
try {
dirty = true;
//从configuration中获取之前解析的MappedStatement(包含了sql的信息)
MappedStatement ms = configuration.getMappedStatement(statement);
//执行executor
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
2. 执行Executor(跟踪到SimpleExecutor继承了BaseExecutor)
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
//创建StatementHandler(RoutingStatementHandler)
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
//通过transaction获取/创建connection(基本的jdbc操作,事务超时时间),执行prepare操作
stmt = prepareStatement(handler, ms.getStatementLog());
//执行PreparedStatementHandler.update
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}
3. 总结
我们本文概述了一些执行Mapper的过程
- 执行Mapper时,调用MapperProxy,初始化MapperMethod。
- 执行MapperMethod,调用SqlSessionTemplate,执行拦截器SqlSessionTemplate$SqlSessionInterceptor。
- openSqlSession,创建SqlSession,创建Executor,注册拦截器(插件)。
- 执行SqlSession,执行插件拦截器,执行Executor,返回结果。
- closeSqlSession。