zoukankan      html  css  js  c++  java
  • 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;
            }
        }
        ...以下省略
    }
    
  • 相关阅读:
    前端--页面提交重置功能
    ztree获取当前选中节点子节点id集合的方法(转载)
    sqlserver锁表、解锁、查看销表 (转载)
    解决前端文件修改后浏览器页面未更新的问题
    简单的上传文件
    如何在Eclipse中查看JDK以及JAVA框架的源码(转载)
    设计模式--观察者模式
    WebService 学习
    学习quartz定时
    JS 中AJAX,Fetch,Axios关系
  • 原文地址:https://www.cnblogs.com/nicori/p/13533576.html
Copyright © 2011-2022 走看看