Mybatis源码剖析---第三讲

Mybatis源码剖析—第三讲

那针对于我们的操作来讲,说应用层。我们使用的是sqlsession的getMapper。进而去获得了dao接口?并不是,是这个dao接口它的实现类的对象。这是需要大家注意的,是dao或者是userdao接口的实现类的对象。这显然是一个多态。
在这里插入图片描述
因为接口是没有办法创建对象的,是没有办法进行实例化的。那么,最终这个方法给我们的这个对象,如果我们要想进行后续使用的话,那它首先应该是个对象。是个类的对象,而不是接口的对象,所以这块我们才推导出这个对象,应该是这个接口实现类的对象。那下面很自然的,大家就会有这样一个疑问了,就是这个dao接口的实现类。它在哪儿呢?我们怎么自始至终在整个编程的过程当中没有见过它呢?因为这是一个典型的动态字节码技术。这是一个典型的动态字节码运行。所谓动态字节码技术的核心是什么呢?
就是这个类,它是在虚拟机当中。运行时创建的。运行时候创建的。那虚拟机结束之后,它就消失了。它和我们原来所写的这些类不一样,不一样,这些类原来我就是实实在在的这些文件。存在磁盘上,我们需要它的时候,我们会通过虚拟机的这个类加载的方式。也就是jvm的这个类加载,把这个类读到虚拟机的内存当中来进行使用。 接下来这个问题就转化成了下面俩个问题:

  1. 这个动态字节码技术它是如何来创建这个userDao或者是xxxDao接口的实现类?
  2. 就是这个实现类当中它又是如何进行实现的?

咱们接着往下看,首先我们先来解决第二个问题:这个实现类当中它又是如何进行实现的?非常简单,我们说过 上面一种方式其实本质上还是调用下面的
在这里插入图片描述
所以我们在实现类中调用下面的sqlSesson方法即可

 interface UserDAO{
                  List<User> queryAllUsers();         
                  save(User user)
             }

          UserDAOImpl implements UserDAO{
                 queryAllUsers(){
                     sqlSession.select("namespace.id",参数)
                 }
                   sqlSession.select("namespace.id",参数)流程,参考上一节
                        |-Excutor
                            |-StatementHandler
                                 |- ParameterHandler , ResultSetHandler
                                              TypeHandler 
                

好,第二个问题解决了,我们再来看第一个问题,如何 创建 UserDAO XXXDAO接口的实现类 ? 动态代理
动态代理的一个使用场景 :
a. 为原始对象(目标)增加【额外功能】 ,适配器模式是增强功能,动态代理是增加额外新功能,概念不同
b. 远程代理 1.网络通信 2.输出传输 (RPC)Dubbo
在这里插入图片描述
在这里插入图片描述
左边的login()方法调用右边的login()方法,典型的RPC,dubbo对此进行了封装,左边是右边的代理人,增加了什么功能呢,数据传输和网络连接

c. 接口实现类,我们看不见实实在在的类文件,但是运行时却能体现出来。无中生有 (我们所需要解决的问题,没有实现类)
所以我们·要用到代理设计模式
是典型的动态代理就是。在静态的文件当中,我们看不见接口的实现类,但是呢?运行的时候我们确实能发现这个接口实现类的存在。那它是怎么做的?它就是典型的代理或者动态代理的体现,这就是我所说的无中生有
动态代理的核心方法 : Proxy.newProxyIntance(ClassLoader,Interface,InvocationHandler)
这个方法什么意思? 类加载器(ClassLoader)所需要我的这个代理类所需要实现的那个接口(Interface)以及所需要增加的那个额外功能(InvocationHandler这个是接口,使用多态,实际上是继承类)
在这里插入图片描述
在这里插入图片描述
我们创建InvocationHandler的实现类,我们最常用的代理模式就是,重写invoke方法,在前后加入处理逻辑
在这里插入图片描述
这时候回到我们第二个问题 : 我们如何去实现这个方法,我们用sqlsesson的selectList的去实现就可以,所以我们将这个selectList()方法写在invoke方法里面就可以,我们通过构造器注入
在这里插入图片描述
namespace 就是接口名,id就是method名
dao接口的名就是
在这里插入图片描述
id就是
在这里插入图片描述
我们通过构造器注入Class拿到它的名字

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
成功运行

在这里插入图片描述
如果我的Dao接口的方法有很多,那就意味着我这个invoke方法的这块的代码,它就不能只是select,它有可能还是insert,有可能还是update,有可能还是delete。所以它这块必定就要做得更复杂,但是整个的流程逻辑和轨迹,和我们这个如出一辙
总结一下:

  1. 为什么要用代理? 接口是不能运行的,它要帮我们去做实现类。所以他要通过代理的方式提供接口的实现类。
  2. 它接口实现类里面该怎么写呢?它接口实现类当中的invoke方法,里面一定最后落实到的就是sqlsession。与之配对的相关方法。

现在我们来看看MyBatis 完成代理创建 的流程

MyBatis 完成代理创建 核心类型 ---> DAO接口的实现类 
     MapperProxy implements InvocationHandler 
     DAO接口Class
     SqlSession 
  
        invoke
              SqlSession.insert 
                         update
                         delete
                         selectOne
                         selectList
  
          SqlCommand:
                1. id = namespace.id
                2. type = insert|delete|select 
                          SqlSession.insert()
                          SqlSession.delete
                          ....
        
     MapperProxyFactory
         Proxy.newProxyInstrace()

首先我们先看看 MapperProxyFactory
在这里插入图片描述
在这里插入图片描述
这一块和我们自己定义的newProxyInstance是一样的,获取dao接口的类加载器,所实现接口,还有一个mapperProxy (invocation handler接口的实现)
在这里插入图片描述
这一块就是实现类,需要sqlSession和mapperInterface, 也就是我们自己定义的这一块内容
在这里插入图片描述
好,我们发现mapperProxy三个参数都是通过构造方法传入的,我们继续跟进
在这里插入图片描述
这一块内容实现了InvovationHandler接口,并且存了sqlSession和dao接口,显然,按照逻辑,我们接下来就要看invoke方法,继续跟进
在这里插入图片描述
由于我们方法中还存在一些toString()方法,wait()方法,notify()方法,这些都是派生于Object,这些不需要sqlSession进行处理,所以这块匹配的就是Object的类的方法进行处理,另一个就是对默认方法进行的处理
而我们的关注点不是这个,而是下面的一个cachedMapperMethod方法ctrl + 鼠标左键跳转
在这里插入图片描述
这一块把method封装成了maspperMethod放入一个Map中
在这里插入图片描述
好,我们接着跟进MapperMethod方法
在这里插入图片描述
为什么要把method封装成了mapperMethod ,它的目的很简单,它就是在这个mappermethod里面封装了两个非常核心的。成员变量,一个叫做sqlcommand,一个叫做methodsignnature,
在这里插入图片描述
这一块,有method方法,dao接口,还有configration

在这里插入图片描述
通过 resolveMappedStatement()方法获得mappedstatement, 如果存在mappedstatement,我们从里面获取namespace.id和sql类型,sql类型是为了后续调用不同的sqlsession来执行,
在这里插入图片描述

在这里插入图片描述
这个是干什么的,跟进去看看
在这里插入图片描述
我们忽略了一件事情,就是方法的返回值以及参数没有处理,所以这个主要针对的是返回值,分页,以及参数
在这里插入图片描述
这一块解决的就是参数的一个处理
然后回到我们之前的
在这里插入图片描述
为什么要对method进行封装,大家想必已经了解了,至此我们就了解了这个动态代理的一个实现流程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值