文章目录
- 1. 相关代码
- 2. 创建SqlSession
- 3. 创建Mapper代理对象
- 4.sql的执行
- 5. sql解析和执行过程中涉及类的介绍
- 5.1 XMLConfigBuilder
- 5.2 XMLMapperBuilder
- 5.3 MapperBuilderAssistant
- 5.4 Cache
- 5.5 ResultMap
- 5.6 XNode
- 5.7 XMLStatementBuilder
- 5.8 MappedStatement
- 5.9 SqlSource
- 5.10 MapperProxyFactory
- 5.11 MapperProxy
- 5.12 SqlSession
- 5.13 Executor
- 5.14 MapperMethod
- 5.15 MapperMethodInvoker
- 5.16 BoundSql
- 5.17 StatementHandler
- 5.18 ParameterHandler
- 5.19 ResultSetHandler
1. 相关代码
@Test
public void test2() throws Exception{
// 1.获取配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
// 2.加载解析配置文件并获取SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
// 3.根据SqlSessionFactory对象获取SqlSession对象
SqlSession sqlSession = factory.openSession();
// 4.通过SqlSession中提供的 API方法来操作数据库
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.selectUserById(1);
System.out.println(user);
// 5.关闭会话
sqlSession.close();
}
2. 创建SqlSession
SqlSession sqlSession = factory.openSession();
@Override
public SqlSession openSession() {
// configuration.getDefaultExecutorType() 获取默认的 Executor的类型 SIMPLE
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
获取默认执行器ExecutorType.SIMPLE。
- 继续看openSessionFromDataSource:
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();
}
}
- 根据事务工厂和默认的执行器类型,创建执行器
/**
* 1. 完成执行器的创建(Executor)
* 2. 完成二级缓存的设置 装饰器模式
* 3. 完成插件逻辑的植入 装饰器模式
* @param transaction 事务管理器
* @param executorType 默认是 Simple
* @return
*/
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) { // 针对 Statement 对象做缓存
executor = new ReuseExecutor(this, transaction);
} else {
// 默认 SimpleExecutor 每一次只是SQL操作都创建一个新的Statement对象
executor = new SimpleExecutor(this, transaction);
}
// 二级缓存开关,settings 中的 cacheEnabled 默认是 true
// 映射文件中 <cache> 标签 --> 创建 Cache对象
// settings 中的 cacheEnabled = true 真正的对 Executor 做了缓存的增强
if (cacheEnabled) {
// 穿衣服的事情 --> 装饰器模式
executor = new CachingExecutor(executor);
}
// 植入插件的逻辑,至此,四大对象已经全部拦截完毕
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
最后返回DefaultSqlSession对象。
总结:创建会话的过程,我们获得了一个DefaultSqlSession,里面包含了一个Executor,Executor是SQL的实际执行对象。
3. 创建Mapper代理对象
// 4.通过SqlSession中提供的 API方法来操作数据库
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
继续F7,
@Override
public <T> T getMapper(Class<T> type) {
return configuration.getMapper(type, this);
}
继续F7,
/**
* 怎么获取 Mapper 接口的代理对象
* 存储关系:
* 1.系统启动的时候
* 接口类型 --》 MapperProxyFactory --》 MapperProxy --> MapperMethod
* 的映射关系存储在 MapperRegistry 中
*
* 获取Mapper代理对象
* 根据传递的接口类型 从 MapperRegistry 中获取对应的
* MapperProxyFactory对象
* 然后 根据 MapperProxyFactory 对象获取 MapperProxy对象
* @param type
* @param sqlSession
* @param <T>
* @return
*/
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// mapperRegistry中注册的有Mapper的相关信息 在解析映射文件时 调用过addMapper方法
return mapperRegistry.getMapper(type, sqlSession);
}
继续F7,
/**
* 获取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方法
这里创建MapperProxy对象
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
实际底层是JDK动态代理。
/**
* 创建实现了 mapperInterface 接口的代理对象
*/
protected T newInstance(MapperProxy<T> mapperProxy) {
// 1:类加载器:2:被代理类实现的接口、3:实现了 InvocationHandler 的触发管理类
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
在代码中发现代理对象是通过JDK动态代理创建,返回的代理对象。而且里面也传递了一个实现了InvocationHandler接口的触发管理类。
总结:获得Mapper对象的过程,实质上是获取了一个JDK动态代理对象(类型是$ProxyN)。这个代理类会继承Proxy类,实现被代理的接口,里面持有了一个MapperProxy类型的触发管理类。
4.sql的执行
4.1 MapperProxy.invoke()
User user = mapper.selectUserById(1);
由于所有的Mapper都是JDK动态代理对象,所以任意的方法都是执行触发管理类MapperProxy的invoke()方法。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// toString hashCode equals getClass等方法,无需走到执行SQL的流程
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else {
// 提升获取 mapperMethod 的效率,到 MapperMethodInvoker(内部接口) 的 invoke
// 普通方法会走到 PlainMethodInvoker(内部类) 的 invoke
return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
然后进入到PlainMethodInvoker的invoke方法.
@Override
public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
// SQL执行的真正起点
return mapperMethod.execute(sqlSession, args);
}
4.2 mapperMethod.execute()
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) { // 根据SQL语句的类型调用SqlSession对应的方法
case INSERT: {
// 通过 ParamNameResolver 处理args[] 数组 将用户传入的实参和指定参数名称关联起来
Object param = method.convertArgsToSqlCommandParam(args);
// sqlSession.insert(command.getName(), param) 调用SqlSession的insert方法
// rowCountResult 方法会根据 method 字段中记录的方法的返回值类型对结果进行转换
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()) {
// 返回值为空 且 ResultSet通过 ResultHandler处理的方法
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);
// 普通 select 语句的执行入口 >>
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;
}
在这一步,根据不同的type(INSERT、UPDATE、DELETE、SELECT)和返回类型:
1)调用convertArgsToSqlCommandParam()将方法参数转换为SQL的参数。
2)调用sqlSession的insert()、update()、delete()、selectOne ()方法。我们以查询为例,会走到selectOne()方法。
4.3 sqlSession.selectOne
@Override
public <T> T selectOne(String statement, Object parameter) {
// 来到了 DefaultSqlSession
// Popular vote was to return null on 0 results and throw exception on too many.
List<T> list = this.selectList(statement, parameter);
if (list.size() == 1) {
return list.get(0);
} else if (list.size() > 1) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return null;
}
}
在SelectList()中,我们先根据command name(Statement ID)从Configuration中拿到MappedStatement。ms里面有xml中增删改查标签配置的所有属性,包括id、statementType、sqlSource、useCache、入参、出参等等.
/**
* SqlSession 是调用者完成数据库操作的 接口
* 那么在SqlSession 内部其实是通过 Executor来完成具体的 数据库操作的
* @param statement com.bobo.mybati.dao.UserMapper.query
* @param parameter
* @param rowBounds
* @param <E>
* @return
*/
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
// MappedStatement 记录了一个 select 标签所具有的所有的信息
MappedStatement ms = configuration.getMappedStatement(statement);
// 如果 cacheEnabled = true(默认),Executor会被 CachingExecutor装饰 wrapCollection(parameter) 对参数进行处理
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()方法。
Executor是第二步openSession的时候创建的,创建了执行器基本类型之后,依次执行了二级缓存装饰,和插件包装。
所以,如果有被插件包装,这里会先走到插件的逻辑。如果没有显式地在settings中配置cacheEnabled=false,再走到CachingExecutor的逻辑,然后会走到BaseExecutor的query()方法。
先忽略插件。
4.4 CachingExecutor.query()
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
// 获取SQL
BoundSql boundSql = ms.getBoundSql(parameterObject);
// 创建CacheKey:什么样的SQL是同一条SQL? >>
// select * from t_user select id,username,password form t_user
// 根据特定的规则生成一个key 保证不冲突
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache();
// cache 对象是在哪里创建的? XMLMapperBuilder类 xmlconfigurationElement()
// 由 <cache> 标签决定 控制二级缓存的开关有两个 一个是 CacheEnabled 全局配置文件中的settings 配置 --》 装饰执行器 Executor CachingExecutor
// 一个是 cache 标签 映射文件中的配置 创建 Cache 对象
if (cache != null) {
// flushCache="true" 清空一级二级缓存 >>
flushCacheIfRequired(ms);
// 在 select 标签中 配置了 useCache 属性
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
// 获取二级缓存
// 缓存通过 TransactionalCacheManager、TransactionalCache 管理
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
// 表示二级缓存中没有数据 那么数据进一步查询处理
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
// 写入二级缓存
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
// 走到 SimpleExecutor | ReuseExecutor | BatchExecutor
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
4.5 BaseExecutor.query方法
/**
* queryStack 和 占位符的作用
* 1.查询 学校 正常查询 --> 放入一级缓存
* 2.查询 学校的学生 正常查询 --> 放入一级缓存
* 3.查询 学生的学校 延迟加载,从缓存中获取
*/
@SuppressWarnings("unchecked")
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
// 异常体系之 ErrorContext
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {
// flushCache="true"时,即使是查询,也清空一级缓存
clearLocalCache();
}
List<E> list;
try {
// 防止递归查询重复处理缓存
queryStack++;
// 查询一级缓存
// ResultHandler 和 ResultSetHandler的区别 一级缓存
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
// 缓存中有数据 说明查询的数据在一级缓存中存在(本地缓存)
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
// 真正的查询流程 一级缓存二级缓存都没有 直接查询数据库中的数据
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
// 延迟加载的内容
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
// 如果LocalCacheScope的值设置为 STATEMENT 则一级缓存失效
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
// 先占位 也就是表示 一级缓存中已经有数据了,只是操作还没有完成 ,相同的操作不用查询数据库了
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
// 三种 Executor 的区别,看doUpdate
// 默认Simple
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
// 移除占位符
localCache.removeObject(key);
}
// 写入一级缓存
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
4.6 SimpleExecutor.doQuery方法
/**
* 到了 具体的数据库操作的步骤了 JDBC
* Connection
* Statement
* PreparedStatement
* @param ms
* @param parameter
* @param rowBounds
* @param resultHandler
* @param boundSql
* @param <E>
* @return
* @throws SQLException
*/
@Override
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();
// 注意,已经来到SQL处理的关键对象 StatementHandler >> 同时会完成 parameterHandler和resultSetHandler的实例化
// 默认创建的是 PreparedStatementHandler
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 获取一个 Statement对象 对占位符处理
stmt = prepareStatement(handler, ms.getStatementLog());
// 执行查询
return handler.query(stmt, resultHandler);
} finally {
// 用完就关闭
closeStatement(stmt);
}
}
执行查询操作,如果有插件包装,会先走到被拦截的业务逻辑。
// 执行查询
return handler.query(stmt, resultHandler);
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
// 如果放开日志 PreparedStatement 其实是一个 PreparedStatementLogger 的代理对象
PreparedStatement ps = (PreparedStatement) statement;
// 到了JDBC的流程
ps.execute(); // 如果是代理对象的话 同样的会进入到 invoke 方法中
// 处理结果集
return resultSetHandler.handleResultSets(ps);
}
执行PreparedStatement的execute()方法,后面就是JDBC包中的PreparedStatement的执行了。
ResultSetHandler处理结果集,如果有插件包装,会先走到被拦截的业务逻辑。
5. sql解析和执行过程中涉及类的介绍
5.1 XMLConfigBuilder
解析全局配置文件和mapper文件;
5.2 XMLMapperBuilder
具体解析mapper文件;
5.3 MapperBuilderAssistant
协助XMLMapperBuilder解析mapper的各种标签,比如缓存标签cashe,select,insert,update,delete等。
5.4 Cache
缓存标签解析完放在类Configuration的caches变量
protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
5.5 ResultMap
解析resultMap标签的结果,最终放在类Configuration的resultMaps 变量
protected final Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");
5.6 XNode
sql标签最终解析方法类Configuration的sqlFragments变量
protected final Map<String, XNode> sqlFragments = new StrictMap<>(“XML fragments parsed from previous mappers”);
5.7 XMLStatementBuilder
select,update,insert,delete等标签的解析器
5.8 MappedStatement
重重重要,select,update,insert,delete标签最终解析结果方法这个类里面。最后放在Configuration的mappedStatements变量
public final class MappedStatement {
private String resource;
private Configuration configuration;
private String id;
private Integer fetchSize;
private Integer timeout;
private StatementType statementType;
private ResultSetType resultSetType;
private SqlSource sqlSource;
private Cache cache;
private ParameterMap parameterMap;
private List<ResultMap> resultMaps;
private boolean flushCacheRequired;
private boolean useCache;
private boolean resultOrdered;
private SqlCommandType sqlCommandType;
private KeyGenerator keyGenerator;
private String[] keyProperties;
private String[] keyColumns;
private boolean hasNestedResultMaps;
private String databaseId;
private Log statementLog;
private LanguageDriver lang;
private String[] resultSets;
MappedStatement() {
// constructor disabled
}
}
// 保存的就是 所有的映射文件的信息 每一个映射文件 对应一个MappedStatement对象
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection")
.conflictMessageProducer((savedValue, targetValue) ->
". please check " + savedValue.getResource() + " and " + targetValue.getResource());
5.9 SqlSource
储存sql语句。(动态sql实现的基础)
5.10 MapperProxyFactory
一个namespace命名空间创建一个MapperProxyFactory,用来创建MapperProxy。
public class MapperProxyFactory<T> {
/**
* MapperProxyFactory 可以创建 mapperInterface 接口的代理对象
* 创建的代理对象要实现的接口
*/
private final Class<T> mapperInterface;
// 缓存
private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return mapperInterface;
}
public Map<Method, MapperMethodInvoker> getMethodCache() {
return methodCache;
}
@SuppressWarnings("unchecked")
/**
* 创建实现了 mapperInterface 接口的代理对象
*/
protected T newInstance(MapperProxy<T> mapperProxy) {
// 1:类加载器:2:被代理类实现的接口、3:实现了 InvocationHandler 的触发管理类
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
5.11 MapperProxy
Mapper接口的代理对象的InvocationHandler,重要,重要。Mapper接口真正的执行逻辑这里。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// toString hashCode equals getClass等方法,无需走到执行SQL的流程
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else {
// 提升获取 mapperMethod 的效率,到 MapperMethodInvoker(内部接口) 的 invoke
// 普通方法会走到 PlainMethodInvoker(内部类) 的 invoke
return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
5.12 SqlSession
接口层类,提供增、删、改、查等各种方法,创建mapper接口的代理类,管理事务。默认实现是DefaultSqlSession。拥有的属性也比较简单,有configuration和executor等。
public class DefaultSqlSession implements SqlSession {
private final Configuration configuration;
private final Executor executor;
private final boolean autoCommit;
private boolean dirty;
private List<Cursor<?>> cursorList;
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}
}
5.13 Executor
Sql执行器。SqlSession是委托Executor 执行sql。
5.14 MapperMethod
对mapper接口的反射方法的包装,由这个类统一执行 INSERT, UPDATE, DELETE, SELECT。
这个类包含两个重要的类:SqlCommand,Sql执行所需要的信息;MethodSignature方法签名。
5.14.1 SqlCommand
保存方法名和方法类型。
public static class SqlCommand {
private final String name; // SQL语句的的名称
private final SqlCommandType type; // SQL 语句的类型
public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
// 获取方法名称
final String methodName = method.getName();
final Class<?> declaringClass = method.getDeclaringClass();
MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
configuration);
if (ms == null) {
if (method.getAnnotation(Flush.class) != null) {
name = null;
type = SqlCommandType.FLUSH;
} else {
throw new BindingException("Invalid bound statement (not found): "
+ mapperInterface.getName() + "." + methodName);
}
} else {
name = ms.getId();
type = ms.getSqlCommandType();
if (type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + name);
}
}
}
}
......
5.14.2 MethodSignature
public static class MethodSignature {
private final boolean returnsMany; // 判断返回是否为 Collection类型或者数组类型
private final boolean returnsMap; // 返回值是否为 Map类型
private final boolean returnsVoid; // 返回值类型是否为 void
private final boolean returnsCursor; // 返回值类型是否为 Cursor 类型
private final boolean returnsOptional; // 返回值类型是否为 Optional 类型
private final Class<?> returnType; // 返回值类型
private final String mapKey; // 如果返回值类型为 Map 则 mapKey 记录了作为 key的 列名
private final Integer resultHandlerIndex; // 用来标记该方法参数列表中 ResultHandler 类型参数的位置
private final Integer rowBoundsIndex; // 用来标记该方法参数列表中 rowBounds 类型参数的位置
private final ParamNameResolver paramNameResolver; // 该方法对应的 ParamNameResolver 对象
/**
* 方法签名
* @param configuration
* @param mapperInterface
* @param method
*/
public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
// 获取接口方法的返回类型
Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
if (resolvedReturnType instanceof Class<?>) {
this.returnType = (Class<?>) resolvedReturnType;
} else if (resolvedReturnType instanceof ParameterizedType) {
this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
} else {
this.returnType = method.getReturnType();
}
this.returnsVoid = void.class.equals(this.returnType);
this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
this.returnsCursor = Cursor.class.equals(this.returnType);
this.returnsOptional = Optional.class.equals(this.returnType);
this.mapKey = getMapKey(method);
this.returnsMap = this.mapKey != null;
// getUniqueParamIndex 查找指定类型的参数在 参数列表中的位置
this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
this.paramNameResolver = new ParamNameResolver(configuration, method);
}
....
}
5.15 MapperMethodInvoker
MapperMethod方法封装的调用器,实现有PlainMethodInvoker, DefaultMethodInvoker. 。
private static class PlainMethodInvoker implements MapperMethodInvoker {
private final MapperMethod mapperMethod;
public PlainMethodInvoker(MapperMethod mapperMethod) {
super();
this.mapperMethod = mapperMethod;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
// SQL执行的真正起点
return mapperMethod.execute(sqlSession, args);
}
}
}
5.16 BoundSql
由SqlSource和传参生成,真正的sql。
5.17 StatementHandler
其中之一的实现PreparedStatementHandler。初始化这个对象同时会初始化ParameterHandler,ResultSetHandler。