您的位置:首页 > 移动开发

(十一)Mybatis Mapper动态代理

2021-04-24 23:32 751 查看

注:代码已托管在GitHub上,地址是:https://github.com/Damaer/Mybatis-Learning ,项目是mybatis-07-MapperDynamicProxy,需要自取,需要配置maven环境以及mysql环境,觉得有用可以点个小星星,小菜鸟在此Thanks~

在之前的代码中我们的运行过程再梳理一下,首先我们执行Test,调用dao接口方法



接口的定义:


调用接口的实现类方法:


最后才是调用真正的sql:


那么我们想是不是可以减少一步呢?我们不用自己实现接口,只需要将接口的名字和mapper文件的namespace对应起来,将接口里面的方法名与sql语句标签的id对应起来是不是就可以了呢?事实上,mybatis提供了这样的做法,这就是mapper动态代理。

mapper动态代理的例子

首先主配置文件(Mybatis.xml),在里面配置数据库连接信息,注册需要扫描的mapper文件:


定义数据库查询的接口,里面每一个接口的名字很重要,需要和mapper里面每一条sql对应起来:


定义mapper文件(namespace要写我们定义的接口,而每条sql的id与我们的接口方法名字对应起来):


那我们在使用的时候:


我们在前面还写到过一个selectStudentMap方法,但是里面调用的是和SelectList一样的sql,在接口的实现类里面我们自己处理了一下,但是现在使用自动实现的话,底层只会调用SelectOne或者SelectList方法,所以这个方法会报错,如果接受类型是list,那么框架会自动使用selectList方法,否则就会选择selectOne()这个方法。

在这里我们使用的是返回的是map,所以自动选择返回selectOne()方法,那么就会报错。如果我们需要使用自动返回map的话,可以自己定一个map,或者返回list之后再处理,这个知识点后面再介绍,有兴趣可以访问:mybatis的mapper返回map结果集

mapper动态代理的原理

打一个断点在sqlSession.getMapper()方法上:



我们可以看到执行下面的接口方法(接口

SqlSession
的方法)

<T> T getMapper(Class<T> var1);

这是一个接口,我们可以看到实现接口的有两个类,一个是DefaultSqlSession,一个是SqlSessionManager,我们需要看的是

DefaultSqlSession
下面的接口:

 publicT getMapper(Classtype) {
    return this.configuration.getMapper(type, this);
  }

我们知道,在创建sqlsession的时候,confiiguration这个配置对象已经创建完成。跟进去,这是使用mapper注册器对象的getMapper方法,将当前的sqlSession对象传递进去:

publicT getMapper(Classtype, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }

我们跟进去源码,可以发现里面使用

knownMappers.get(type)
来获取mapper代理工厂,这个konwnMappers是一个hashMap,这个hashMap里面已经初始化了mapperProxyFactory对象了,获取到工厂对象之后,再去使用sqlSession实例化:

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

实例化的时候,使用了mapper动态代理:

public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

从下面的debug结果中我们可以看到,这是动态代理的结果:

此文章仅代表自己(本菜鸟)学习积累记录,或者学习笔记,如有侵权,请联系作者删除。人无完人,文章也一样,文笔稚嫩,在下不才,勿喷,如果有错误之处,还望指出,感激不尽~

技术之路不在一时,山高水长,纵使缓慢,驰而不息。

公众号:秦怀杂货店

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: