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);
}
复制代码