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;
        }
    }
    ...以下省略
}
posted @ 2020-08-20 10:21  Ninon  阅读(270)  评论(0编辑  收藏  举报