0
点赞
收藏
分享

微信扫一扫

Mybatis源码解析:动态代理让sql执行更安全高效


Mybatis源码解析:动态代理让sql执行更安全高效_sql

Mybatis为什么要使用动态代理对SqlSession进行增强?

Mybatis源码解析:动态代理让sql执行更安全高效_安全_02


在ibatis时代,是直接通过sqlSession进行调用的

SqlSession sqlSession = sqlSessionFactory.openSession(true);
UserInfo userInfo = sqlSession.selectOne("org.apache.ibatis.atest.UserInfoMapper.selectById", 1);

这种方式有什么缺点呢?

调用的方法有可能写错,实际要执行的sql并没有配置
传入的参数有可能写错,因为入参是Object类型
返回值有可能写错,因为返回值也是Object类型

但是这些问题在编译的时候并不会暴露,只有在运行的时候才会暴露

鉴于ibatis的这些问题,Mybatis使用了动态代理减少了错误的发生,并且让api变的更简洁易用

SqlSession sqlSession = sqlSessionFactory.openSession(true);
UserInfoMapper mapper = sqlSession.getMapper(UserInfoMapper.class);
UserInfo userInfo = mapper.selectById(1);

代理的主要流程如下图所示

Mybatis源码解析:动态代理让sql执行更安全高效_动态代理_03

创建代理对象

用上一节的例子来debug动态代理的过程,一步一步追

SqlSession sqlSession = sqlSessionFactory.openSession(true);
UserInfoMapper mapper = sqlSession.getMapper(UserInfoMapper.class);
UserInfo userInfo = mapper.selectById(1);

之前的文章说过sqlSessionFactory的实现类是DefaultSqlSessionFactory,所以openSession返回的是DefaultSqlSession,追一下
DefaultSqlSession#getMapper方法

org.apache.ibatis.session.defaults.DefaultSqlSession#getMapper

Mybatis源码解析:动态代理让sql执行更安全高效_安全_04


org.apache.ibatis.session.Configuration#getMapper

Mybatis源码解析:动态代理让sql执行更安全高效_java_05


org.apache.ibatis.binding.MapperRegistry#getMapper

Mybatis源码解析:动态代理让sql执行更安全高效_动态代理_06


org.apache.ibatis.binding.MapperProxyFactory#newInstance(org.apache.ibatis.session.SqlSession)

Mybatis源码解析:动态代理让sql执行更安全高效_apache_07


整体逻辑并不复杂,利用MapperProxyFactory生成MapperProxy,而MapperProxy实现了InvocationHandler,所以返回的代理类就是MapperProxy,所以当执行Mapper接口的返回时,会首先进入MapperProxy#invoke方法

同时MapperProxy包装了SqlSession,从这我们就能猜到,后续MapperProxy肯定是利用调用的方法,拼装sql对应的id,然后交给SqlSession来执行查询

执行动态代理方法

当执行Mapper接口的任何方法时,都会进入MapperProxy#invoke方法(MapperProxy实现了InvocationHandler接口)

org.apache.ibatis.binding.MapperProxy#invoke

Mybatis源码解析:动态代理让sql执行更安全高效_安全_08


如果执行的是Object类中的方法,直接反射执行即可,否则执行cachedInvoker方法得到MapperMethodInvoker,然后调用其invoke方法org.apache.ibatis.binding.MapperProxy#cachedInvoker

Mybatis源码解析:动态代理让sql执行更安全高效_apache_09


org.apache.ibatis.util.MapUtil#computeIfAbsent

Mybatis源码解析:动态代理让sql执行更安全高效_apache_10


把要执行的方法封装为MapperMethodInvoker,并通过ConcurrentHashMap缓存下来,MapUtil#computeIfAbsent就是一个简单的工具类,利用computeIfAbsent来保证线程安全

如果是接口的默认方法则封装为DefaultMethodInvoker
否则封装为PlainMethodInvoker(一般情况,我们都不会对接口提供default方法,所以我们看一下PlainMethodInvoker#invoke的逻辑)

Mybatis源码解析:动态代理让sql执行更安全高效_安全_11


调用MapperMethod#execute方法,和我们之前分享的参数处理器和SqlSession的执行流程接上了哈,至此整个执行流程分析完毕

参考博客

[1]https://www.jianshu.com/p/46c6e56d9774


举报

相关推荐

0 条评论