Mybatis源码流程剖析
一、Mybatis初始化流程
1.我们如何初始化Mybatis
InputStream inputStream = Resources.getResourcesAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputstream);
2.分析源码
首先我们找到SqlSessionFactoryBuilder类的build方法(这里使用了建造者模式)
public SqlSessionFactory build(Reader reader) {
return build(reader, null, null);
}
这里调用了另一个重载方法
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
// XMLConfigBuilder 是专门解析mybatis的配置文件的类
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
// parser.parse()的返回值是一个Configuration对象
// 然后调用了一个新的重载方法
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
Mybatis在初始化的时候,会将Mybatis的配置信息全部加载到内存中,使用Configuration实例来维护。Configuration对象的结构与xml文件的配置几乎一样,初始化配置文件的本质就是创建Configuration对象,将解析的xml数据封装到Configuration内部的属性中。
接下来我们需要研究下parser.parse()是怎么获得Configuration对象的
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
// 解析 XML Configuration 节点
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
private void parseConfiguration(XNode root) {
try {
// issue #117 read properties first
// 解析<properties />标签
propertiesElement(root.evalNode("properties"));
// 解析<settings />标签
Properties settings = settingsAsProperties(root.evalNode("settings"));
// 加载自定义的VFS实现类
loadCustomVfs(settings);
// 加载logImpl实现类
loadCustomLogImpl(settings);
// 解析 <typeAlias />标签
typeAliasesElement(root.evalNode("typeAliases"));
// 解析<plugins />标签
pluginElement(root.evalNode("plugins"));
// 解析<objectFactory />标签
objectFactoryElement(root.evalNode("objectFactory"));
// 解析<objectWrapperFactory />标签
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
// 解析<reflectorFactory />标签
reflectorFactoryElement(root.evalNode("reflectorFactory"));
// 赋值<settings />标签至configuration属性
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
// 解析<environments />标签
environmentsElement(root.evalNode("environments"));
// 解析<databaseIdProvider />标签
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
// 解析<typeHandlers />标签
typeHandlerElement(root.evalNode("typeHandlers"));
// 解析<mappers />标签
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
在上面的代码中我们需要注意解析<mappers >标签的语句。mappers标签用来引用mappers.xml文件或者mapper接口的目录。
如这样的mapper.xml,这样的一个select标签会在初始化配置文件时解析封装成一个MapperStatement对象,然后存储在Configuration对象的mappedStatements属性中。mapperdStatements是一个HashMap,key=全限定类名+方法名,value=对应的MapperStatement对象
<select id="getUser" resultType="user" >
select * from user where id=#{id}
</select>
在Configuration类中对应的属性:
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection")
.conflictMessageProducer((savedValue, targetValue) ->
". please check " + savedValue.getResource() + " and " + targetValue.getResource());
到此,xml文件的解析就结束了,然后会回调build方法,返回一个SqlSessionFactory的默认实现对象(这个对象会携带刚刚解析完成的configuration对象)
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
二、SqlSession执行SQL流程
1.如何使用SqlSessionFactory执行SQL语句
Sqlsession sqlSession = factory.openSession();
List<User> list = sqlSession.selectList("com.example.mapper.UserMapper.getUserByName");
2.源码分析
首先,我们需要了解SqlSession。它是一个接口,有两个的实现类:DefaultSqlSession(默认)和SqlSessionManager(弃用)。
SqlSession是Mybatis中用于和数据库交互的顶层类,通常与ThreadLocal绑定,一个会话使用一个sqlSession,使用完成后需要close。
在SqlSession中最重要的两个参数,一个是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;
}
public DefaultSqlSession(Configuration configuration, Executor executor) {
this(configuration, executor, false);
}
Executor作为执行器的接口,有三个常用的实现类:
BatchExecutor:重用语句并执行批量更新
ReuseExecutor:重用预处理语句 prepared statements
SimpleExecutor:普通执行器,默认
我们从factory.openSession()
的源代码开始分析
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
这里调用了一个重构方法
/**
* ExecutorType Executor的类型
* TransactionIsolationLevel 事务的隔离级别
* autoCommit 是否开启事务
*/
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);
// 根据参数创建指定的executor
final Executor executor = configuration.newExecutor(tx, execType);
// 最终返回的是DefaultSqlSession
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();
}
}
然后再看sqlSession.selectList
的源代码
@Override
public <E> List<E> selectList(String statement) {
return this.selectList(statement, null);
}
@Override
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
// 根据传入的全限定名+方法名从configuration中取出MappedStatement对象
MappedStatement ms = configuration.getMappedStatement(statement);
// 调用Executor中的方法处理,其中rowBounds是用来逻辑分页的,warpCollection(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的执行
三、Executor执行流程
进入executor.query()
/**
* 此方法在SimpleExecutor的父类BaseExecutor中
*/
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
// 根据传入的参数动态获得SQL语句,最后生成一个BoundSql对象
BoundSql boundSql = ms.getBoundSql(parameter);
// 为本次查询创建缓存的key
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
// 调用重载方法
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
@SuppressWarnings("unchecked")
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
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()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
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();
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 {
// 最终调用doQuery()方法
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;
}
/**
* SimpleExecutor实现父类的doQuery()的抽象方法
*/
@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();
// 根据传入的参数创建StatementHandler对象
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 创建jdbc中的statement对象
stmt = prepareStatement(handler, ms.getStatementLog());
// 调用StatementHandler对象中的query方法进行处理
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
/**
* 创建statement对象的方法
*/
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
// getConnection方法经过重重调用,最终会走到openConnection()方法中
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());
handler.parameterize(stmt);
return stmt;
}
protected Connection getConnection(Log statementLog) throws SQLException {
Connection connection = transaction.getConnection();
if (statementLog.isDebugEnabled()) {
return ConnectionLogger.newInstance(connection, statementLog, queryStack);
} else {
return connection;
}
}
@Override
public Connection getConnection() throws SQLException {
if (connection == null) {
openConnection();
}
return connection;
}
protected void openConnection() throws SQLException {
if (log.isDebugEnabled()) {
log.debug("Opening JDBC Connection");
}
// 从连接池获取连接
connection = dataSource.getConnection();
if (level != null) {
connection.setTransactionIsolation(level.getLevel());
}
setDesiredAutoCommit(autoCommit);
}
综述,executor对象的query()方法,几经波折最后会创建一个StatementHandler对象,并将必要的参数传递给statementHandler,使用statementHandler来完成数据库的查询,最终返回一个List结果集。
Executor组件的作用:
- 根据传递的参数,完成SQL的动态解析,生成BoundSql对象,供StatementHandler使用
- 为查询创建缓存,已提高性能
- 创建JDBC的statement连接对象,传递给StatementHandler对象,返回List查询结果
四、StatementHandler执行流程
StatementHandler对象/组件主要完成三件事:
- JDBC的preparedStatement类型的对象,创建的过程中我们使用的SQL字符串会包含若干个?占位符,我们需要对占位符进行设置值。StatementHandler通过parameterize(statement)方法对statement进行设值(这一步在创建statement对象的方法中已经执行完了)
- 执行sql
- StatementHandler通过
List query(Statement statement ,ResuletHandler resuletHandler)
方法来完成执行Statement和将Statement对象返回的resultSet封装成List
首先我们看handler.parameterize(stmt)
的源码
/**
* PreparedStatementHandler实现StatementHandler接口的方法
*/
@Override
public void parameterize(Statement statement) throws SQLException {
// 使用parameterHandler对象来完成对statement的设值
parameterHandler.setParameters((PreparedStatement) statement);
}
/**
* ParameterHandler实现StatementHandler接口的方法,用来对某一个Statement进行设置参数
*/
@Override
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
// 每一个mapping都有一个TypeHandler,根据TypeHandler对preparedStatement进行参数设置
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
// 设置参数
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException | SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}
从上面的代码中我们知晓,handler.parameterize(stmt)
调用了parameterHandler.setParameters((PreparedStatement) statement)
。
setParameters方法根据我们输入的参数,对statement对象的占位符进行赋值(这里面涉及到TypeHandler对象)
StatementHandler的第二步会调用statement.execute(sql)
方法执行sql,第三步会调用query(Statement statement ,ResuletHandler resuletHandler)
方法将statement对象执行后的ResultSet结果集转换成List结果集,源码如下:
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
String sql = boundSql.getSql();
statement.execute(sql);
// 使用ResultSetHandler来封装处理execute的ResultSet方法
return resultSetHandler.handleResultSets(statement);
}
//
// HANDLE RESULT SETS
//
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
// 每个ResultSet对应一个Object对象,实际上每个Object是一个List<Object>对象
// 在不考虑存储过程的多ResultSet的情况,普通的查询,就会有一个ResultSet,也就是说最后生成的multiplesResults最多就一个一个元素
final List<Object> multipleResults = new ArrayList<>();
int resultSetCount = 0;
// 1.通过getFirstResultSet()方法获得ResultSet的包装类ResultSetWrapper对象。其实就是首个ResultSet对象
ResultSetWrapper rsw = getFirstResultSet(stmt);
// 3.获得ResultMaps数组(在不考虑存储过程的多ResultSet情况,普通的查询,就一个ResultSet,也就是说resultMaps就一个元素)
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
while (rsw != null && resultMapCount > resultSetCount) {
// 获得第i个ResultMap对象
ResultMap resultMap = resultMaps.get(resultSetCount);
// 实际处理ResultSet的方法,将结果添加到multipleResults里面
handleResultSet(rsw, resultMap, multipleResults, null);
// 2.通过getNextResultSet()方法,获得下一个ResultSet对象,并封装成ResultSetWrapper对象
rsw = getNextResultSet(stmt);
// 清理
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
// mappedStatement.resultSets只在存储过程中使用,所以下面的代码可以忽略
String[] resultSets = mappedStatement.getResultSets();
if (resultSets != null) {
while (rsw != null && resultSetCount < resultSets.length) {
ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
if (parentMapping != null) {
String nestedResultMapId = parentMapping.getNestedResultMapId();
ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
handleResultSet(rsw, resultMap, null, parentMapping);
}
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
}
return collapseSingleResultList(multipleResults);
}
五、Mapper代理方式
实际上,我们在使用Mybatis执行sql时,一般不会使用sqlSession.selectList()
的方法,而是采用代理的方式,如下:
public static void main(String[] args) {
//前三步都相同
InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = factory.openSession();
//这里不再调用SqlSession的api,而是获得了接口对象,调用接口中的方法。
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> list = mapper.getUserByName("tom");
}
但是,我们并没有实现UserMapper,为什么可以直接调用呢?答案很简单:动态代理技术
补充一个细节,Mybatis初始化时产生的Configuration对象中有一个属性叫MapperRegistry,它内部维护了一个HashMap,用于mapper接口的工厂类。
<mappers>
<mapper class="com.lagou.mapper.UserMapper"/>
<package name="com.lagou.mapper"/>
</mappers>
当解析mappers标签时
- 如果解析到的是mapper配置文件,它会将配置文件中的增删改查标签封装成MappedStatement对象,存入mappedStatements中,然后放入到Configuration中
- 如果解析到的是接口,会创建此接口对应的MapperProxyFactory对象,存入到HashMap中,key为此接口的Class对象,value为此接口对应的MapperProxyFactory对象
1.getMapper()方法执行流程
查看sqlSession.getMapper(UserMapper.class )
的源码
@Override
public <T> T getMapper(Class<T> type) {
// 调用configuration的getMapper()方法
return configuration.getMapper(type, this);
}
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// 从mapperRegistry中获得代理对象
return mapperRegistry.getMapper(type, sqlSession);
}
@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// 从MapperRegistry中的HashMap中获得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 {
// 调用工厂的newInstance方法获得结果
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
public T newInstance(SqlSession sqlSession) {
// 创建一个MapperProxy对象
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
// 调用重构方法
return newInstance(mapperProxy);
}
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
// 使用JDK的动态代理技术获得代理对象
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
使用JDK的动态代理技术获得代理对象,它意味着jdk动态代理的InvocationHandler接口的实现在mapperProxy中。继续翻阅MapperProxy
源码
public class MapperProxy<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -4724728412955527868L;
private static final int ALLOWED_MODES = MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
| MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC;
private static final Constructor<Lookup> lookupConstructor;
private static final Method privateLookupInMethod;
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
private final Map<Method, MapperMethodInvoker> methodCache;
//构造,传入了 SqlSession,说明每个session中的代理对象的不同的!
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethodInvoker> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
static {
Method privateLookupIn;
try {
privateLookupIn = MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class);
} catch (NoSuchMethodException e) {
privateLookupIn = null;
}
privateLookupInMethod = privateLookupIn;
Constructor<Lookup> lookup = null;
if (privateLookupInMethod == null) {
// JDK 1.8
try {
lookup = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
lookup.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new IllegalStateException(
"There is neither 'privateLookupIn(Class, Lookup)' nor 'Lookup(Class, int)' method in java.lang.invoke.MethodHandles.",
e);
} catch (Exception e) {
lookup = null;
}
}
lookupConstructor = lookup;
}
// invoke方法的具体细节
@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 {
return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
...
}
2.invoke()方法执行流程
我们知道,在动态代理返回了示例后,我们就可以直接调用mapper类中的方法了,但代理对象调用方法,执行是在MapperProxy中的invoke方法中
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) { // 如果是Object定义的方法,直接调用
return method.invoke(this, args);
} else {
// 获得 MapperMethodInvoke 对象,重点在这:MapperMethodInvoke最终调用了method对象的invoke方法。
return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
/**
*
* Method的具体实现方法
*/
private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
try {
// A workaround for https://bugs.openjdk.java.net/browse/JDK-8161372
// It should be removed once the fix is backported to Java 8 or
// MyBatis drops Java 8 support. See gh-1929
MapperMethodInvoker invoker = methodCache.get(method);
if (invoker != null) {
return invoker;
}
return methodCache.computeIfAbsent(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 {
// 不是的化,构造一个PlainMethodInvoke对象
return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
}
});
} catch (RuntimeException re) {
Throwable cause = re.getCause();
throw cause == null ? re : cause;
}
}
/**
* Returns {@code true} if this method is a default
* method; returns {@code false} otherwise.
*
* A default method is a public non-abstract instance method, that
* is, a non-static method with a body, declared in an interface
* type.
*
* @return true if and only if this method is a default
* method as defined by the Java Language Specification.
* @since 1.8
*/
public boolean isDefault() {
// Default methods are public non-abstract instance methods
// declared in an interface.
return ((getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) ==
Modifier.PUBLIC) && getDeclaringClass().isInterface();
}
这里需要查看下PlainMethodInvoker,它是一个内部类,实现了MapperMethodInvoker接口,最终的最终会调用到mapperMethod.execute(sqlSession, args)
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 {
//实际上还是走到了MapperMethod的execute方法
return mapperMethod.execute(sqlSession, args);
}
}
进入execute方法
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
// 判断mapper中的方法类型,最终调用的还是SqlSession中的方法
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);
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;
}
至此,我们常用的Mapper方式的源码追踪完。