为啥mybatis的mapper只有接口没有实现类,但它却能工作?(全网独一份

  • 接口测试

接口我们就用UserMapper,我们来写个代理对象。

为啥mybatis的mapper只有接口没有实现类,但它却能工作?(全网独一份_第1张图片

ok,一个简单的动态代理例子送给你们,上面代码中关键生成动态代理对象的关键代码是:

  • loader: 用哪个类加载器去加载代理对象

  • interfaces:动态代理类需要实现的接口

  • h:动态代理方法在执行时,会调用h里面的invoke方法去执行

源码分析

好啦,上面该做的准备已经都准备好了,我们对mybatis的这个mapper接口大概都有些思路了,下面我们去正式验证一下,那么肯定就要去看源码了。我们只是去验证上面的mapper接口问题,所以不需要去看全部的代码,当然如果你看整个流程下来的话,会更加清晰。

论证猜想,我们可以采用结果导向的方式去看源码,从获取mapper那里开始看,也就是

主要从sqlSession.getMapper(UserMapper.class);这里开始,先看整个UserMapper是不是被动态代理的。ok,我们进入代码中:

  • org.apache.ibatis.session.SqlSessionManager#getMapper

为啥mybatis的mapper只有接口没有实现类,但它却能工作?(全网独一份_第2张图片

继续走到Configuration方法里,Configuration是mybatis所有配置相关的地方,mybatis-cfg.xml、UserMapper.xml等文件都会被预先加载到Configuration里。

  • org.apache.ibatis.session.Configuration#getMapper

这时候,我们发现Configuration里面出现了一个mapperRegistry,翻译过来可以理解为mapper的注册器,其实在加载UserMapper.xml的时候,我们就需要在mapperRegistry里面进行注册,所有,我们可以从这里面进行获取。继续走~

  • org.apache.ibatis.binding.MapperRegistry#getMapper

为啥mybatis的mapper只有接口没有实现类,但它却能工作?(全网独一份_第3张图片

ok,这里分为了两步:

  • knownMappers.get(type);

  • 获取已知的加载过的mapper中获取出mapper代理工厂

  • mapperProxyFactory.newInstance(sqlSession);

  • 代理工厂生成动态代理返回

我们一步步分析,别急,knownMappers其实是个map,根据userMapper.class获取MapperProxyFactory:

所以knownMappers必然是源码前面的步骤中set进去的。我们先找找,到底是哪里set进去的。找呀找,找到这里:

  • org.apache.ibatis.builder.xml.XMLMapperBuilder#bindMapperForNamespace

为啥mybatis的mapper只有接口没有实现类,但它却能工作?(全网独一份_第4张图片

我们看这个boundType,是通过Resources.classForName(namespace);生成的class,Resources.classForName底层其实就是调用Class.forName生成的反射对象,而参数是namespace,namespacne不正是com.lfq.UserMapper嘛:

完美!!Class.forName(com.lfq.UserMapper)生成反射对象。论证了我们第一点猜想。生成的boundType在被configuration.addMapper(boundType);所以就有了:

  • org.apache.ibatis.session.Configuration#addMapper

  • org.apache.ibatis.bin为啥mybatis的mapper只有接口没有实现类,但它却能工作?(全网独一份_第5张图片
    ding.MapperRegistry#addMapper

为啥mybatis的mapper只有接口没有实现类,但它却能工作?(全网独一份_第6张图片

上面的代码,就给我论证了这个MapperProxyFactory是哪里来的,MapperProxyFactory里面其实就一个参数mapperInterface,就是反射生成的这个对象。ok,第一个猜想已经论证完毕,接着我们看刚才说到的第二点:动态代理。

回到mapperProxyFactory.newInstance(sqlSession); 这个MapperProxyFactory就是我们刚刚new出来的,我们打开newInstance方法看看:

  • org.apache.ibatis.binding.MapperProxyFactory#newInstance(MapperProxy)
    为啥mybatis的mapper只有接口没有实现类,但它却能工作?(全网独一份_第7张图片
    终于在里面看到Proxy.newProxyInstance了,好激动呀。又论证了第二点的动态代理猜想 上面代码中,首先把sqlSession, mapperInterface, methodCache三个参数封装到MapperProxy中,而MapperProxy是实现了InvocationHandler接口的方法,因此动态代理被调用的时候,会进入到MapperProxy的invoke方法中。

sqlSession是必须的,因为操作数据库需要用到sqlsession。具体invoke里面的内容,我们不做多分析啦,刚兴趣的同学自己去看下源码哈。可以猜想:找到对应的sql,然后执行sql操作,哈哈哈。

总结

好啦,今天的内容就到这里啦~

如果你喜欢我的文章,欢迎关注我的公众号:java思维导图,给我点个在看或者转发一下,万分感谢哈!

互动环节:

最后不做小调查了,我们来个留言互动吧:以你所学知识,请大胆猜想一下,spring data jpa为什么只需要声明符合命名规范的接口即可,而不需要写实现类?他的底层实现可能用了什么技术?

(完)

原创 吕一明

最后不做小调查了,我们来个留言互动吧:以你所学知识,请大胆猜想一下,spring data jpa为什么只需要声明符合命名规范的接口即可,而不需要写实现类?他的底层实现可能用了什么技术?

(完)

原创 吕一明

你可能感兴趣的:(程序员,架构,移动开发,android)