mybatis源码解析--mapper代理对象的生成过程

我们平常在使用mybatis的时候只需要生成mapper接口和与其对应的xml文件就行了,我们就可以把这个接口当作一个bean,可以往其他的bean中注入了。我们没有实现mapper接口,为什么可以使用接口中的方法呢?原因是虽然我们没有实现接口,但是通过配置文件,spring为我们生成了接口的代理类。
让我们从配置文件入手,从源码中一探究竟。
mybatis源码解析--mapper代理对象的生成过程_第1张图片
MapperScannerConfigurer这个类是负责扫描mapper接口所在的包的,它把扫描到的接口解析成一个个的bean定义(BeanDefinition),来看一下源码:
在这里插入图片描述
MapperScannerConfigurer实现了两个重要接口,如图所示。
实现BeanDefinitionRegistryPostProcessor接口,我们可以自定义注册bean过程,要实现的方法是
postProcessBeanDefinitionRegistry()
实现InitializingBean接口的afterPropertiesSet()方法,可以在bean创建之后初始化的时候做一些操作。
现在进入MapperScannerConfigurer的postProcessBeanDefinitionRegistry()方法
mybatis源码解析--mapper代理对象的生成过程_第2张图片
该方法内部把扫描mapper接口的工作委托给了ClassPathMapperScanner类,该类继承自ClassPathBeanDefinitionScanner,进入它的scan()方法:
mybatis源码解析--mapper代理对象的生成过程_第3张图片
ClassPathBeanDefinitionScanner中的doScan()方法:
mybatis源码解析--mapper代理对象的生成过程_第4张图片
doScan方法真正的负责生成bean定义。
ClassPathMapperScanner重载的doScan()方法:
mybatis源码解析--mapper代理对象的生成过程_第5张图片
重载的doScan方法对生成的mapper的bean定义做了进一步处理,进入processBeanDefinitions()方法:
mybatis源码解析--mapper代理对象的生成过程_第6张图片
红色部分为该方法的核心,mapperInterface设置的值是mapper接口的带包名的路径名称;
definition.setBeanClass()把原来的BeanClass的类型替换成了MapperFactoryBean类型,这个是Mapper接口加载定义阶段最重要的一步。是生成代理类的关键。
查看MapperFactoryBean的定义:
mybatis源码解析--mapper代理对象的生成过程_第7张图片
mybatis源码解析--mapper代理对象的生成过程_第8张图片
mybatis源码解析--mapper代理对象的生成过程_第9张图片
MapperFactoryBean实现了FactoryBean接口,实现了FactoryBean接口的类型在调用getBean(beanName)既通过名称获取对象时,返回的对象不是本身类型的对象,而是通过实现接口中的getObject()方法返回的对象。
mybatis源码解析--mapper代理对象的生成过程_第10张图片
MapperFactoryBean实现了FactoryBean接口InitializingBean接口,在对象初始化的时候会调用它的afterPropertiesSet方法,该方法中首先调用了checkDaoConfig()方法,MapperFactoryBean重载的checkDaoConfig()如下:
mybatis源码解析--mapper代理对象的生成过程_第11张图片
Configuration configuration = getSqlSession().getConfiguration();这一句中的getSqlSession()获取的SqlSession
对象就是文章开头的配置文件中配置的。
Configuration 是一个重要的配置类mybatis源码解析--mapper代理对象的生成过程_第12张图片
进入 configuration.addMapper(this.mapperInterface)方法中:
在这里插入图片描述
在configuration内部对Mapper的操作都委托给了mapperRegistry对象,进入它的addMapper(type)方法,这里的参数type就是一个mapper接口的类型(如:com.st.mapper.UserMapper.java):
mybatis源码解析--mapper代理对象的生成过程_第13张图片
knownMappers.put(type, new MapperProxyFactory(type));这一步为我们创建了mapper 的代理工厂类对象,并把它放入了knownMappers这个Map中。MapperProxyFactory这个类我们下面再讲。
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
这两句完成了mapper接口对应的xml文件的解析,xml文件中的每一个方法都被解析成了一个MappedStatement对象(代码太长,不再展开),并添加到了configuration对象中:
mybatis源码解析--mapper代理对象的生成过程_第14张图片

对上面的内容的总结:
mapper接口的定义在bean加载阶段会被替换成MapperFactoryBean类型,在spring容器初始化的时候会给我们生成MapperFactoryBean类型的对象,在该对象生成的过程中调用afterPropertiesSet()方法,为我们生成了一个
MapperProxyFactory类型的对象存放于Configuration里的MapperRegistry对象中,同时解析了mapper接口对应的xml文件,把每一个方法解析成一个MappedStatement对象,存放于Configuration里的mappedStatements
这个Map集合中。

下面看一下MapperFactoryBean的getObject()方法,看看mapper代理对象是如何生成的:
mybatis源码解析--mapper代理对象的生成过程_第15张图片
mybatis源码解析--mapper代理对象的生成过程_第16张图片
跟踪代码最后调用的是MapperRegistry.getMapper()方法给我们返回了mapper代理对象。

现在来看一下MapperProxyFactory这个类:
mybatis源码解析--mapper代理对象的生成过程_第17张图片
MapperProxy是被代理的对象,看下这个类:
mybatis源码解析--mapper代理对象的生成过程_第18张图片
在invoke()方法中最终执行的是mapperMethod.execute(sqlSession, args);方法。
来看一下MapperMethod这个类:
mybatis源码解析--mapper代理对象的生成过程_第19张图片
execute()这个方法最终负责执行我们mapper接口中方法,它会判断要执行的方法的类型,然后调用sqlSession对应的方法类型来执行,并放回结果。

你可能感兴趣的:(源码解读)