代理方式源码分析

回顾代理模式的写法:

/**
 * mapper代理方式
 */
public void test2() throws IOException {

  InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
  SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
  SqlSession sqlSession = factory.openSession();

  // 使用JDK动态代理对mapper接口产生代理对象
  IUserMapper mapper = sqlSession.getMapper(IUserMapper.class);

  //代理对象调用接口中的任意方法,执行的都是动态代理中的invoke方法
  List<Object> allUser = mapper.findAllUser();

}

这里我们就需要带着问题去看源码

  • SqlSession是如何生成接口的代理对象的

  • 代理对象执行方法时(invoke),是如何进行一些处理的

getMapper()源码解析

我们看getMapper()之前,首先思考一下,使用代理模式开发,需要怎么做?

  1. 创建Dao接口,编写方法,编写对应的mapper映射文件

  2. 在核心配置类中扫描Dao接口,一般是使用扫描包的形式

所以,我们先去看解析核心配置中mappers标签的源码,看看扫描后,他是将我们配置的类放到了哪里?

通过Mybatis初始化过程的源码分析,我们直接来到XMLConfigBuilder.mapperElement()方法

这里可以看到,如果扫描包的形式,会调用configuration.addMappers()方法

通过源码,我们发现了Mybatis会获取包下所有类对象Class,然后通过new MapperProxyFactory<>(type)创建出代理工厂对象,Map, MapperProxyFactory> knownMappers存放到Map中

  • key:类对象

  • value:MapperProxyFactory代理工厂对象

到此,我们就知道了,在Mybatis初始化过程中,会将配置的Dao类保存到Map中

接着,我们去查看getMapper()源码

最终就来到了MapperRegistry对象中,也就是刚刚注册Dao接口的地方,通过源码会发现,他先从Map中取出该类对应的MapperProxyFactory,然后调用mapperProxyFactory.newInstance(sqlSession)来构建代理对象

  1. 创建MapperProxy对象,这个对象实现类InvocationHandler代理必备接口

  2. 通过JDK动态代理的方式,构建出Dao对应的代理对象并返回

所以,通过源码,我们最终知道了:

  • Mybatis初始化时,会扫描配置的包,把Dao接口和对应的MapperProxyFactory以键值对形式保存到Map中

  • 通过getMapper()获取代理对象时,是使用JDK动态代理的形式创建出了MapperProxy代理对象

invoke()源码分析

通过前面的学习,我们知道代理类不管执行什么方法,都会走invoke()方法,所以我们直接取MapperProxy查看invoke方法的源码

通过源码,我们可以看到,首先会判断方法类型,是增删改查中的哪一种,然后其实还是调用的SqlSession中的增删改查方法

查询方法里,会根据返回值不同进行不同的请求,我们看一下返回列表也就是List类型的方法

可以看到,实际还是执行的 sqlSession.selectList()方法,然后传入StatementId等参数

到这里关于Mybatis的执行流程就梳理完成了,如果您没有看到之前的文章,

Mybatis整体流程总结

Mybatis整体流程总结

Last updated

Was this helpful?