MapperRegistry
的实例,有一个属性 Map<Class<?>, MapperProxyFactory<?>> knownMappers
:
MapperProxyFactory
对象,是Mapper代理类 MapperProxy
的工厂,创建 MapperProxy
对象执行Mapper类中定义的方法。
类型是 Map<String, MappedStatement>
:
MappedStatement MappedStatement
MyBatis分三个步骤执行查询过程:
DefaultSqlSession session.getMapper(UserMapper.class) userMapper.findList()
DefaultSqlSessionFactory.openSession
:
public SqlSession openSession(boolean autoCommit) { // 第一步 // Configuration中:defaultExecutorType = ExecutorType.SIMPLE return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit); } // 第二步 //openSessionFromDataSource关键代码: final Executor executor = configuration.newExecutor(tx, execType); return new DefaultSqlSession(configuration, executor, autoCommit); 复制代码
Executor从 Configuration.newExecutor
方法中创建:
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; } 复制代码
newExecutor
的执行过程如下:
SimpleExecutor
; CachingExecutor
对象; interceptorChain.pluginAll
加入拦截器 Interceptor
列表。
DefaultSqlSession
从 Configuration.mapperRegistry
中获取Mapper的实现对象:
// 第一步 // DefaultSqlSesison: public <T> T getMapper(Class<T> type) { return configuration.<T>getMapper(type, this); } // 第二步 // Configuration: public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return mapperRegistry.getMapper(type, sqlSession); } // 第三步 // MapperRegistry: // 从属性knownMappers中获取MapperProxyFactory对象,获取到后执行newInstance获取MapperProxy,即Mapper类的实现对象。 public <T> T getMapper(Class<T> type, SqlSession sqlSession) { 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); } } // 第四步 // MapperProxyFactory 创建MapperProxy对象 protected T newInstance(MapperProxy<T> mapperProxy) { return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); } public T newInstance(SqlSession sqlSession) { final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); } 复制代码
由上面 MapperProxyFactory
代码可知,
每次执行 session.getMapper
都会创建 MapperProxy
对象及其代理对象
,所以应避免多次调用 session.getMapper
。
MyBatis使用JDK代理方式, MapperProxy
实现了 InvocationHandler
接口,所以Mapper接口类的实现方法,是在 MapperProxy.invoke
方法里执行。
invoke
中,获取或创建一个 MapperMethod
对象,然后执行 MapperMethod.execute
方法。
//// 获取MapperMethod对象 private MapperMethod cachedMapperMethod(Method method) { MapperMethod mapperMethod = methodCache.get(method); if (mapperMethod == null) { mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()); methodCache.put(method, mapperMethod); } return mapperMethod; } //// 执行execute final MapperMethod mapperMethod = cachedMapperMethod(method); return mapperMethod.execute(sqlSession, args); 复制代码
MapperMethod
有两个属性:
private final SqlCommand command; private final MethodSignature method; 复制代码
SqlCommand
有两个属性:
SqlCommand创建时,会从Configuration中获取MappedStatement对象,获取到则用于name和type的赋值:
String statementId = mapperInterface.getName() + "." + methodName; if (configuration.hasStatement(statementId)) { return configuration.getMappedStatement(statementId); } 复制代码
private final boolean returnsMany; // configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray() private final boolean returnsMap; // private final boolean returnsVoid; // void.class.equals(this.returnType) private final boolean returnsCursor; // org.apache.ibatis.cursor.Cursor.class.equals(this.returnType) private final Class<?> returnType; ////// private final ParamNameResolver paramNameResolver; // new ParamNameResolver(configuration, method) 复制代码
根据 command.type
,判断执行的操作:
public Object execute(SqlSession sqlSession, Object[] args) { Object result; switch (command.getType()) { 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); 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; } 复制代码
在execute调用的 executeFor*
方法中,最终调用的是 sqlSession.select*
方法。
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { try { // 第一步,从Configuration中取出MappedStatement对象 // statement : interfaceName + "." + methodName MappedStatement ms = configuration.getMappedStatement(statement); // 第二步,执行查询 // executor : 前面Configuration.newExecutor创建的executor,默认SimpleExecutor return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); } catch (Exception e) { throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } } 复制代码
executor.query的调用链:
BaseExecutor.query -> BaseExecutor.queryFromDatabase -> SimpleExecutor.doQuery
SimpleExecutor.doQuery:
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { Configuration configuration = ms.getConfiguration(); // 第一步 创建RoutingStatementHandler StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); // 第二步 调用StatementHandler.prepare创建Statement stmt = prepareStatement(handler, ms.getStatementLog()); // 第三步 执行StatementHandler.query return handler.<E>query(stmt, resultHandler); } finally { closeStatement(stmt); } } 复制代码
configuration.newStatementHandler中创建的是 RoutingStatementHandler
,然后设置拦截器:
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; } 复制代码
RoutingStatementHandler
是一种委派模式,根据 MappedStatement.statementType
的不同,返回不同的 StatementHandler
实现类:
// 代理 private final StatementHandler delegate; public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { switch (ms.getStatementType()) { case STATEMENT: delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; case PREPARED: delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; case CALLABLE: delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; default: throw new ExecutorException("Unknown statement type: " + ms.getStatementType()); } } 复制代码
创建 java.sql.Statement
对象,调用链:
RoutingStatementHandler.prepare -> BaseStatementHandler.prepare -> PreparedStatementHandler.instantiateStatement
instantiateStatement
是 BaseStatementHandler
的抽象方法,供子类实现。
// PreparedStatementHandler protected Statement instantiateStatement(Connection connection) throws SQLException { if (mappedStatement.getResultSetType() != null) { return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY); } else { return connection.createStatement(); } } 复制代码
有了 Statement
之后,就可以拿来进行查询了:
@Override public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; ps.execute(); return resultSetHandler.<E> handleResultSets(ps); } 复制代码