啃下MyBatis源码系列目录
啃下MyBatis源码 - 为什么要看MyBatis源码及源码结构
啃下MyBatis源码 - org.apache.ibatis.logging包源码分析
啃下MyBatis源码 - org.apache.ibatis.datasource包源码分析
啃下MyBatis源码 - org.apache.ibatis.cache包源码分析
啃下MyBatis源码 - MyBatis核心流程三大阶段之初始化阶段
啃下MyBatis源码 - MyBatis核心流程三大阶段之代理阶段(binding模块分析)
啃下MyBatis源码 - MyBatis核心流程三大阶段之数据读写阶段
--------------------------------------------------------------------------------------------------------------------------
啃下MyBatis源码 - MyBatis核心流程三大阶段之代理阶段(binding模块分析)
1.MyBatis是如何做到面向Mapper接口编程?
2.代理阶段流程梳理
--------------------------------------------------------------------------------------------------------------------------
1.MyBatis是如何做到面向Mapper接口编程?
只有接口,没有实现类,那么我们很容易会想到是通过解析xml配置文件+动态代理来实现的。我们先来说下MyBatis动态代理实际做了一些什么事情,我们正常编写的代码:
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User uer = userMapper.selectByPrimarKey(1);
MyBatis动态代理后执行的为下面这段代码:
SqlSession sqlSession = sqlSessionFactory.openSession();
User uer = sqlSession.selectOne("com.en.iot.mapper."+"UserMapper.selectByPrimarKey",1);
我们可以看到MyBatis动态代理主要做的是翻译的工作,主要翻译的内容有三点:
1、找到Session中对应的方法执行
2、找到命名空间和方法名
3、传递参数
这三项工作主要是由MapperMethod这个类来实现的,解读这个类之前,我们有必要对binding模块进行一个整体的分析:
MapperRegistry:为MyBatis配置类Configuration类中一个重要的属性,它是mapper接口和对应的代理对象工厂的注册中心;
public class MapperRegistry {
private final Configuration config;
//mapper接口和对应的代理对象工厂之间的关系
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();
...
}
MapperProxyFactory:用于生成mapper接口动态代理的实例对象;
public class MapperProxyFactory<T> {
...
//key为mapper接口中的某个方法的method对象,value为对应的MapperMethod
private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
...
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
}
MapperProxy:实现InvocationHandler接口,它是增强mapper接口的实现;
接着跟进cachedInvoker(method).invoke(proxy, method, args, sqlSession)方法
我们可以看到在cachedInvoker中判断了一下是选用DefaultMethodInvoker还是PlainMethodInvoker
我们可以看到在PlainMethodInvoker类中封装了一个MapperMethod对象,然后在invoke方法中的execute方法中最终通过增删改查的类型来调用增强的方法,当然调用前先用参数解析器过滤一下参数。
那么我们大胆猜测一下,调用execute的这个MapperMethod类中一定保持着Mapper接口中对应方法以及对应的sql语句的信息。
通过观察这三个对象的构造方法我们可以看到,这三个对象全部是从Configuration类中获取信息,由此证实了我们的猜想,MapperMethod类中通过这三个对象建立mapper接口和配置文件sql语句的联系。
2.代理阶段流程梳理
1、先从Configuration配置类MapperRegistry对象中获取mapper接口和对应的代理对象工厂信息(MapperProxyFactory)
2、利用代理对象工厂MapperProxyFactory创建实际代理类(MapperProxy)
3、在MapperProxy类中通过MapperMethod类对象内保存的中对应方法的信息,以及对应的sql语句的信息进行分析,最终确定对应的增强方法进行调用。