Mybatis源码分析获取Mapper

这次分析的入口是

StudentMapper studentMapper=sqlSession.getMapper(StudentMapper.class);

根据上篇分析我们这里获得的sqlSession是DefaultSqlSession,

public class DefaultSqlSession implements SqlSession {
    private Configuration configuration;
    private Executor executor;
    private boolean autoCommit;
    private boolean dirty;

    public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
        this.configuration = configuration;
        this.executor = executor;
        this.dirty = false;
        this.autoCommit = autoCommit;
    }
    }

1.我们进入getMapper方法

 public <T> T getMapper(Class<T> type) {
        return this.configuration.getMapper(type, this);
    }

这里没有做什么处理,接下来进入configuration.getMapper中

 public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        return this.mapperRegistry.getMapper(type, sqlSession);
    }

利用我们开始解析xml获得的mapperRegistry获取,继续跟进

private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap();//这是我们mapperRegistry中保存的
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        MapperProxyFactory mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);//通过上面的HashMap获取mapperProxyFactory
        if(mapperProxyFactory == null) {
            throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
        } else {
            try {
                return mapperProxyFactory.newInstance(sqlSession);//生成代理类
            } catch (Exception var5) {
                throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
            }
        }
    }

这里就要说一下什么是MapperProxyFactory?

翻译成中文就是映射代理工厂。

private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap();
public MapperProxyFactory(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

上面构造函数的代码首先会把之前在mapper.xml中配置的那些mapper接口注入进去,这里我们也会有一个方法缓存,我们每个方法都会对应一个MapperMethod其中保存我们已经解析过的sql。接下来我们就会生成我们的代理映射类。

public T newInstance(SqlSession sqlSession) {
        MapperProxy mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
        return this.newInstance((MapperProxy)mapperProxy);
    }

mapperProxy就是我们的代理类,接下来进入我们的代理类之中。Mybatis实现的是Jdk动态代理,在代理之中最重要的当然是invoke,接下来我们分析。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if(Object.class.equals(method.getDeclaringClass())) {
            try {
                return method.invoke(this, args);
            } catch (Throwable var5) {
                throw ExceptionUtil.unwrapThrowable(var5);
            }
        } else {
            MapperMethod mapperMethod = this.cachedMapperMethod(method);
            return mapperMethod.execute(this.sqlSession, args);
        }
    }

    private MapperMethod cachedMapperMethod(Method method) {
        MapperMethod mapperMethod = (MapperMethod)this.methodCache.get(method);
        if(mapperMethod == null) {
            mapperMethod = new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
            this.methodCache.put(method, mapperMethod);
        }

        return mapperMethod;
    }

1.上面的invoke之中我们首先判断method方法的拥有者类是不是和object.class相等。如果相等就直接执行Invoke。
2.如果不相等通过this.cachedMapperMethod(method);获取我们该方法的缓存映射。
3。调用mapperMethod.execute(this.sqlSession, args); 这是真正的执行过程。

这里MapperMethod非常重要我们这里详细分析:

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, method);
    }
    }

在MapperMethod维护了两个变量SqlCommand 和MethodSignature ,SqlCommand类获取处理的唯一标识及SQL语句类型,MethodSignature类对业务接口方法的入参类型及出参类型进行处理。
在SqlCommand的构造函数中有

public static class SqlCommand {
        private final String name;//保存我们唯一标识id
        private final SqlCommandType type;//保存我们sql语句类型

        public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
            String statementName = mapperInterface.getName() + "." + method.getName();
            MappedStatement ms = null;
            if(configuration.hasStatement(statementName)) {
                ms = configuration.getMappedStatement(statementName);
            } else if(!mapperInterface.equals(method.getDeclaringClass())) {
                String parentStatementName = method.getDeclaringClass().getName() + "." + method.getName();
                if(configuration.hasStatement(parentStatementName)) {
                    ms = configuration.getMappedStatement(parentStatementName);
                }
            }

            if(ms == null) {
                if(method.getAnnotation(Flush.class) == null) {
                    throw new BindingException("Invalid bound statement (not found): " + statementName);
                }

                this.name = null;
                this.type = SqlCommandType.FLUSH;
            } else {
                this.name = ms.getId();
                this.type = ms.getSqlCommandType();
                if(this.type == SqlCommandType.UNKNOWN) {
                    throw new BindingException("Unknown execution method for: " + this.name);
                }
            }

        }
        }

当我们代理实例生成之后,我们利用jdk反射Proxy.newProxyInstance()方法生成我们的代理类。

protected T newInstance(MapperProxy<T> mapperProxy) {
        return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
    }

至此我们获取Mapper过程全部分析完毕。简而言之就是生成了利用Proxy动态代理反射生成。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值