Mybatis-plus 源码执行全流程解析
废话 少数流程开始:
1、业务入口:userMapper.insertBatch(entityList);
执行到代理类: $Proxy222 (com.sun.proxy) 开始走代理流程,然后到了代理类:
idea 执行流程取出栈信息:
invoke:89, MybatisMapperProxy (com.baomidou.mybatisplus.core.override)
提前生成sqlSession ,地方如下:
2、代理类:public class MybatisMapperProxy
// 当前代理类、方法名、保存的参数对象,可能多个@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {if (Object.class.equals(method.getDeclaringClass())) {return method.invoke(this, args);} else {//核心接口进入,带着生成的sqlSessionreturn cachedInvoker(method).invoke(proxy, method, args, sqlSession);}} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}}
来到:
// private final Map methodCache; 类似缓存操作private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {try {// 集合的操作方法,通过接口回调返回数据return CollectionUtils.computeIfAbsent(methodCache, method, m -> {if (m.isDefault()) {try {if (privateLookupInMethod == null) {return new DefaultMethodInvoker(getMethodHandleJava8(method));} else {return new DefaultMethodInvoker(getMethodHandleJava9(method));}} catch (IllegalAccessException | InstantiationException | InvocationTargetException| NoSuchMethodException e) {throw new RuntimeException(e);}} else {return new PlainMethodInvoker(new MybatisMapperMethod(mapperInterface, method, sqlSession.getConfiguration()));}});} catch (RuntimeException re) {Throwable cause = re.getCause();throw cause == null ? re : cause;}}
进入新的invoke 方法:
@Overridepublic Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {//private final MybatisMapperMethod mapperMethod 方法名对象return mapperMethod.execute(sqlSession, args);//核心操作}
3、来到 public class MybatisMapperMethod 类:
// private final MapperMethod.MethodSignature method ;方法的类名
public Object execute(SqlSession sqlSession, Object[] args) {Object result;switch (command.getType()) {//MapperMethod.SqlCommand command; 对象case INSERT: {//新增会走这里,点击进入,合成参数数据,进入Object param = method.convertArgsToSqlCommandParam(args);//通过方法名、参数,执行并返回执行结果,进入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);// TODO 这里下面改了if (IPage.class.isAssignableFrom(method.getReturnType())) {result = executeForIPage(sqlSession, args);// TODO 这里上面改了} else {result = sqlSession.selectOne(command.getName(), param);if (method.returnsOptional()&& (result == null || !method.getReturnType().equals(result.getClass()))) {result = Optional.ofNullable(result);}}}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;}
4、来到 public class MapperMethod 的内部类MethodSignature
//private final ParamNameResolver paramNameResolver; 参数分解器public Object convertArgsToSqlCommandParam(Object[] args) {return paramNameResolver.getNamedParams(args);//进入}
5、来到:public class ParamNameResolver
public Object getNamedParams(Object[] args) {final int paramCount = names.size();if (args == null || paramCount == 0) {return null;} else if (!hasParamAnnotation && paramCount == 1) {Object value = args[names.firstKey()];return wrapToMapIfCollection(value, useActualParamName ? names.get(0) : null);} else {final Map param = new ParamMap<>();int i = 0;for (Map.Entry entry : names.entrySet()) {param.put(entry.getValue(), args[entry.getKey()]);// add generic param names (param1, param2, ...)final String genericParamName = GENERIC_NAME_PREFIX + (i + 1);// ensure not to overwrite parameter named with @Paramif (!names.containsValue(genericParamName)) {param.put(genericParamName, args[entry.getKey()]);}i++;}return param;}}
最后返回:
下面重点分析:
result = rowCountResult(sqlSession.insert(command.getName(), param));
点击 sqlSession.insert(command.getName(), param) 进入:三个实现类的其中一个
根据上游入口判断进入spring的类:
public class SqlSessionTemplate implements SqlSession, DisposableBean
6、来到 SqlSessionTemplate
//private final SqlSession sqlSessionProxy;方法的全路径、执行参数@Overridepublic int insert(String statement, Object parameter) {return this.sqlSessionProxy.insert(statement, parameter);//进入}
三个实现类:
来到子类 public class DefaultSqlSession implements SqlSession
7、DefaultSqlSession
@Overridepublic int insert(String statement, Object parameter) {return update(statement, parameter);//进入执行}
来到:
//private final Executor executor;执行器接口//private final Configuration configuration; 配置类@Overridepublic int update(String statement, Object parameter) {try {dirty = true;MappedStatement ms = configuration.getMappedStatement(statement);//创建声明,进入return executor.update(ms, wrapCollection(parameter));//正式执行} catch (Exception e) {throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);} finally {ErrorContext.instance().reset();//实例资源清除}}
点击configuration.getMappedStatement(statement) 进入
来到 public class MybatisConfiguration extends Configuration 此类为mybatisplus的类,继承的mybatis的配置类Configuration 。
8、MybatisConfiguration 类
//此id就是mapper的全路径,在此服务中应该也是唯一的值@Overridepublic MappedStatement getMappedStatement(String id) {return this.getMappedStatement(id, true);//正式获取声明}
来到:
//protected final Map mappedStatements @Overridepublic MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {if (validateIncompleteStatements) {buildAllStatements();//上游传的true,进入}return mappedStatements.get(id);//在此处返回}
点击: buildAllStatements() 进入父类Configuration,组装的细节后面我们会详细分享
protected void buildAllStatements() {parsePendingResultMaps();if (!incompleteCacheRefs.isEmpty()) {synchronized (incompleteCacheRefs) {incompleteCacheRefs.removeIf(x -> x.resolveCacheRef() != null);}}if (!incompleteStatements.isEmpty()) {synchronized (incompleteStatements) {incompleteStatements.removeIf(x -> {x.parseStatementNode();return true;});}}if (!incompleteMethods.isEmpty()) {synchronized (incompleteMethods) {incompleteMethods.removeIf(x -> {x.resolve();return true;});}}}
返回后进入 executor.update(ms, wrapCollection(parameter));进入切面类
public class Plugin implements InvocationHandler
//切面方法@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {Set methods = signatureMap.get(method.getDeclaringClass());if (methods != null && methods.contains(method)) {//private final Interceptor interceptor;拦截器接口return interceptor.intercept(new Invocation(target, method, args));//进入拦截器}return method.invoke(target, args);//进行执行业务} catch (Exception e) {throw ExceptionUtil.unwrapThrowable(e);}}
点击:
来到:public class OptimisticLockerInterceptor implements Interceptor mybatis 中的类
@Override@SuppressWarnings({"unchecked", "rawtypes"})public Object intercept(Invocation invocation) throws Throwable {Object[] args = invocation.getArgs();MappedStatement ms = (MappedStatement) args[0];if (SqlCommandType.UPDATE != ms.getSqlCommandType()) {return invocation.proceed();}Object param = args[1];if (param instanceof Map) {Map map = (Map) param;//updateById(et), update(et, wrapper);Object et = map.getOrDefault(Constants.ENTITY, null);if (et != null) {// entityString methodId = ms.getId();String methodName = methodId.substring(methodId.lastIndexOf(StringPool.DOT) + 1);TableInfo tableInfo = TableInfoHelper.getTableInfo(et.getClass());if (tableInfo == null || !tableInfo.isWithVersion()) {return invocation.proceed();}TableFieldInfo fieldInfo = tableInfo.getVersionFieldInfo();Field versionField = fieldInfo.getField();// 旧的 version 值Object originalVersionVal = versionField.get(et);if (originalVersionVal == null) {return invocation.proceed();}String versionColumn = fieldInfo.getColumn();// 新的 version 值Object updatedVersionVal = this.getUpdatedVersionVal(fieldInfo.getPropertyType(), originalVersionVal);if (PARAM_UPDATE_METHOD_NAME.equals(methodName)) {AbstractWrapper, ?, ?> aw = (AbstractWrapper, ?, ?>) map.getOrDefault(Constants.WRAPPER, null);if (aw == null) {UpdateWrapper> uw = new UpdateWrapper<>();uw.eq(versionColumn, originalVersionVal);map.put(Constants.WRAPPER, uw);} else {aw.apply(versionColumn + " = {0}", originalVersionVal);}} else {map.put(Constants.MP_OPTLOCK_VERSION_ORIGINAL, originalVersionVal);}versionField.set(et, updatedVersionVal);return invocation.proceed();}}return invocation.proceed();//点击进入}
来到:public class Invocation
public Object proceed() throws InvocationTargetException, IllegalAccessException {return method.invoke(target, args);//进入
}
到了:public final class Method extends Executable
@CallerSensitive@ForceInline // to ensure Reflection.getCallerClass optimization@HotSpotIntrinsicCandidatepublic Object invoke(Object obj, Object... args)throws IllegalAccessException, IllegalArgumentException,InvocationTargetException{if (!override) {Class> caller = Reflection.getCallerClass();checkAccess(caller, clazz,Modifier.isStatic(modifiers) ? null : obj.getClass(),modifiers);}MethodAccessor ma = methodAccessor; // read volatileif (ma == null) {ma = acquireMethodAccessor();}return ma.invoke(obj, args);//进入}
进入:
三个实现类
9、来到 public class MybatisCachingExecutor implements Executor 实现类 mybatisplus包中
@Overridepublic int update(MappedStatement ms, Object parameterObject) throws SQLException {flushCacheIfRequired(ms);//刷新清除缓存,下次查询此表,会到数据库查,点击// private final Executor delegate;执行器执行return delegate.update(ms, parameterObject);//核心执行,点击}
来到:
private void flushCacheIfRequired(MappedStatement ms) {Cache cache = ms.getCache();if (cache != null && ms.isFlushCacheRequired()) {tcm.clear(cache);//清除缓存}}
点击 delegate.update(ms, parameterObject);
10、到了 public abstract class BaseExecutor implements Executor
@Overridepublic int update(MappedStatement ms, Object parameter) throws SQLException {ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());if (closed) {throw new ExecutorException("Executor was closed.");}clearLocalCache();//清除缓存return doUpdate(ms, parameter);//正式执行}
点击:
protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException;
抽象方法的重写:有mybatis和plus的两组实现
10、 到:public class MybatisSimpleExecutor extends AbstractBaseExecutor
@Overridepublic int doUpdate(MappedStatement ms, Object parameter) throws SQLException {Statement stmt = null;try {Configuration configuration = ms.getConfiguration();StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);//生成执行的声明,里面很复杂,后期我们很专题讲解stmt = prepareStatement(handler, ms.getStatementLog(), false);//拿数据源重点,进入return stmt == null ? 0 : handler.update(stmt);//正式执行,点击} finally {closeStatement(stmt);//关闭声明}}
点击 prepareStatement(handler, ms.getStatementLog(), false);
private Statement prepareStatement(StatementHandler handler, Log statementLog, boolean isCursor) throws SQLException {Statement stmt;Connection connection = getConnection(statementLog);//取数据源,进入stmt = handler.prepare(connection, transaction.getTimeout());封装数据源到声明里//游标不支持返回null.if (stmt == null && !isCursor) {return null;} else {handler.parameterize(stmt);return stmt;}}
11、到了父类 public abstract class BaseExecutor implements Executor
protected Connection getConnection(Log statementLog) throws SQLException {// protected Transaction transaction;Connection connection = transaction.getConnection();//获取数据源,进入if (statementLog.isDebugEnabled()) {return ConnectionLogger.newInstance(connection, statementLog, queryStack);} else {return connection;}}
点击发现常用的三种实现:
显然 进入 mybatis-spring 包里的SpringManagedTransaction
10、来到 public class SpringManagedTransaction implements Transaction 类
@Overridepublic Connection getConnection() throws SQLException {if (this.connection == null) {openConnection();//获取连接,进入}return this.connection;}
点击 openConnection()
private void openConnection() throws SQLException {//通过spring的工具类DataSourceUtils 获取 数据库连接connection(JDK包里的),进入this.connection = DataSourceUtils.getConnection(this.dataSource);this.autoCommit = this.connection.getAutoCommit();//自动提交的获取//是否连接、事务的判断this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);LOGGER.debug(() -> "JDBC Connection [" + this.connection + "] will"+ (this.isConnectionTransactional ? " " : " not ") + "be managed by Spring");}
来到:
public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {try {return doGetConnection(dataSource);//点击}catch (SQLException ex) {throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection", ex);}catch (IllegalStateException ex) {throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection: " + ex.getMessage());}}
点击:
public static Connection doGetConnection(DataSource dataSource) throws SQLException {Assert.notNull(dataSource, "No DataSource specified");ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {conHolder.requested();if (!conHolder.hasConnection()) {logger.debug("Fetching resumed JDBC Connection from DataSource");conHolder.setConnection(fetchConnection(dataSource));}return conHolder.getConnection();}// Else we either got no holder or an empty thread-bound holder here.logger.debug("Fetching JDBC Connection from DataSource");Connection con = fetchConnection(dataSource);//重点进入if (TransactionSynchronizationManager.isSynchronizationActive()) {try {// Use same Connection for further JDBC actions within the transaction.// Thread-bound object will get removed by synchronization at transaction completion.ConnectionHolder holderToUse = conHolder;if (holderToUse == null) {holderToUse = new ConnectionHolder(con);}else {holderToUse.setConnection(con);}holderToUse.requested();TransactionSynchronizationManager.registerSynchronization(new ConnectionSynchronization(holderToUse, dataSource));holderToUse.setSynchronizedWithTransaction(true);if (holderToUse != conHolder) {TransactionSynchronizationManager.bindResource(dataSource, holderToUse);}}catch (RuntimeException ex) {// Unexpected exception from external delegation call -> close Connection and rethrow.releaseConnection(con, dataSource);throw ex;}}return con;}
来到:
private static Connection fetchConnection(DataSource dataSource) throws SQLException {Connection con = dataSource.getConnection();//点击进入,dataSource 的实现类if (con == null) {throw new IllegalStateException("DataSource returned null from getConnection(): " + dataSource);}return con;}
点击:dataSource.getConnection()发现好的实现类,应该进入哪一个啊??
根据业务判断:进入NandaoDataSource
public class NandaoDataSource extends AbstractTenantDataSource implements DataSource, NandaoDataSourceMXBean, MBeanRegistration, AutoCloseable{
@Overridepublic Connection getConnection() throws SQLException {if (provider == null) {throw new Exception("provider is null");}return getConnection(provider.getUserId());//业务封装回去自定义数据源}
进入
public Connection getConnection(String userId) throws SQLException {for (int retry = 1; retry <= retryTimes; retry++) {UserDbInfo dbInfo = userDbInfoInfoService.getDatabaseInfo(userId);return getDataSource(dbInfo).getConnection();}}
这是获取数据源的流程,分析到此,下篇我们分析真正执行数据库的流程 handler.update(stmt);,敬请期待!
上一篇: 从现在开始
下一篇: 生命因你而美丽高中作文