美文网首页
Mybatis【11】-- Mybatis Mapper动态代理

Mybatis【11】-- Mybatis Mapper动态代理

作者: 秦怀杂货店 | 来源:发表于2021-02-03 23:59 被阅读0次

    [TOC]

    1.回顾Mybatis执行sql的流程

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

    image

    接口的定义:


    image

    调用接口的实现类方法:


    image

    最后才是调用真正的sql:


    image

    上面的代码是在接口实现类里面自己去执行id,查找并执行mapper文件里面的sql,那么我们想是不是可以减少一步呢?

    如果我们不用自己实现接口,只需要将接口的名字和mapper文件的namespace对应起来,将接口里面的方法名与sql语句标签的id对应起来是不是就可以了呢?

    事实上,mybatis提供了这样的做法,这就是mapper动态代理。

    2.mapper动态代理怎么写?

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

    image

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

    image

    定义mapper文件(namespace是接口的全限定类名):

    image

    那我们在使用的时候,需要使用sqlSession.getMapper()方法,里面传入的是接口,意思是通过接口的全限定名,也就是前面在mapper.xml文件里面配置的命名空间nameSpace,这样一来,就是获取到了代理类,将daomapper.xml文件关联起来了,而每条sqlid与我们的接口方法名字对应起来)

    image

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

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

    3.mapper动态代理怎么做的?

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

    image

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

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

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

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

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

    public <T> T getMapper(Class<T> type, 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结果中我们可以看到,这是动态代理的结果,我们看到的是dao,但是动态代理对这个dao做了增强,实则是一个mapperProxy

    image

    【作者简介】
    秦怀,公众号【秦怀杂货店】作者,技术之路不在一时,山高水长,纵使缓慢,驰而不息。这个世界希望一切都很快,更快,但是我希望自己能走好每一步,写好每一篇文章,期待和你们一起交流。

    相关文章

      网友评论

          本文标题:Mybatis【11】-- Mybatis Mapper动态代理

          本文链接:https://www.haomeiwen.com/subject/ppevtltx.html