MyBatis Mapper动态代理源码分析
调试到测试用service
这里可以看到,Spring创建的类是MapperProxy,里面代理的接口就是我们需要调用的TPayOrderMapper
MapperProxy.invoke部分源码
public class MapperProxy<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache;
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
//判断是否Object的方法,如toString、hashCode直接调用
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
//判断这个方法不是抽象并且不是静态的public,并且是接口
if (this.isDefaultMethod(method)) {
return this.invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
//通过method获取构造时传入的MapperMethod
MapperMethod mapperMethod = this.cachedMapperMethod(method);
//执行方法代码
return mapperMethod.execute(this.sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
return (MapperMethod)this.methodCache.computeIfAbsent(method, (k) -> {
return new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
});
}
...以下省略
}
看到上面这个InvocationHandler是不是很熟悉,这里是之前JDK动态代理源码分析文章讲到的调用处理类需要实现的接口,ProxyClassFactory生成的代理类会调用invoke,因此可以证明MyBatis是使用JDK动态代理实现的。
MapperMethod.execute部分源码
public class MapperMethod {
private final MapperMethod.SqlCommand command;
private final MapperMethod.MethodSignature method;
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new MapperMethod.SqlCommand(config, mapperInterface, method);
this.method = new MapperMethod.MethodSignature(config, mapperInterface, method);
}
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
Object param;
//解析xml的类型为SELECT
switch(this.command.getType()) {
case INSERT:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
break;
case UPDATE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
break;
case DELETE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
break;
case SELECT:
//返回结果为void并参数只存在一个ResultHandler参数
if (this.method.returnsVoid() && this.method.hasResultHandler()) {
this.executeWithResultHandler(sqlSession, args);
result = null;
} else if (this.method.returnsMany()) {
//返回结果是否集合类型或数组
result = this.executeForMany(sqlSession, args);
} else if (this.method.returnsMap()) {
//返回结果是否Map
result = this.executeForMap(sqlSession, args);
} else if (this.method.returnsCursor()) {
//返回结果是否cursor类型
result = this.executeForCursor(sqlSession, args);
} else {
//其他类型
param = this.method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(this.command.getName(), param);
if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + this.command.getName());
}
//判断结果为null和方法回调结果为原始类型并且方法返回类型不为void
if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
} else {
return result;
}
}
//集合类型或数组查询
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
Object param = this.method.convertArgsToSqlCommandParam(args);
List result;
//是否有使用rowBounds分页
if (this.method.hasRowBounds()) {
RowBounds rowBounds = this.method.extractRowBounds(args);
result = sqlSession.selectList(this.command.getName(), param, rowBounds);
} else {
//name为com.gof.pay.index.dao.TPayOrderMapper.selectByMobile
result = sqlSession.selectList(this.command.getName(), param);
}
if (!this.method.getReturnType().isAssignableFrom(result.getClass())) {
return this.method.getReturnType().isArray() ? this.convertToArray(result) : this.convertToDeclaredCollection(sqlSession.getConfiguration(), result);
} else {
return result;
}
}
...以下省略
}