Mybatis核心源码分析之Mapper初始化(一)

如果项目中的ORM框架用的是Mybatis,只需要配置一下数据源,然后再定义一个mapper接口和一个xml文件就可以实现Java对象与数据库表之间的映射,从而可以实现对数据库的访问。使用起来非常简单,这得益于Mybatis强大的封装能力。下面我们分析一下Mybatis的核心源码,看看Mybatis是怎么实现的。本篇主要介绍Mapper的初始化。
Mapper是一个接口,需要有具体的实现类来完成它定义的功能,Mybatis给所有的Mapper创建了动态代理,这些动态代理是通过Spring提供的FactoryBean来创建的(如果你对FactoryBean不熟悉,可以看看笔者的另一篇博文:BeanFactory与FactoryBean的区别及设计思想)。

1 为Mapper注册bean

Mapper的bean注册采用的是Import模式,也就是需要在某个类上(配置类或启动类)加Import注解并指定注册器,由该注册器完成注册。Mybatis是定义了一个注解MapperScan,
在这里插入图片描述
在MapperScan上加了Import注解,并指定了MapperScannerRegistrar为Mapper的注册器。MapperScan这个注解加在Springboot项目的启动类上就可以完成Mapper的注册。
在这里插入图片描述
在为配置类(启动类也作为配置类来处理)创建bean时,会调用ConfigurationClassPostProcessor.processConfigBeanDefinitions()方法,在这里会为启动类创建一个bean并放入candidates里,
在这里插入图片描述
在ConfigurationClassParser.parse()方法里最终会去收集启动类的所有Import资源,
在这里插入图片描述
并将这些资源放入到Map里。
在这里插入图片描述
在这里插入图片描述
我们再回到ConfigurationClassPostProcessor.processConfigBeanDefinitions()方法,
在这里插入图片描述
图中红框里的方法最终会去调用ImportBeanDefinitionRegistrar.registerBeanDefinitions()方法。所以要想自定义注册器来实现注册bean,需要自定义的注册器实现ImportBeanDefinitionRegistrar接口。
下面我们重点看下MapperScannerRegistrar这个类:
在这里插入图片描述
该类实现了ImportBeanDefinitionRegistrar接口。在方法的第一行是获取MapperScan注解的元数据,其中就包含在启动类上加的包名。
在这里插入图片描述
这个包名指定了Mapper所在的路径。
在这里插入图片描述
在方法的最后一行调用了ClassPathMapperScanner.doScan()方法
在这里插入图片描述
在这里会扫描包下的所有Mapper并生成bean。在processBeanDefinitions()方法里有两个比较重要的地方,
在这里插入图片描述
首先是将bean的构造器参数设为了Mapper类,然后是把bean的beanClass改为了MapperFactoryBean。下面会给bean设置一些属性,如sqlSessionFactory、sqlSessionTemplate等。
在这里插入图片描述
我们再看看MapperFactoryBean,这里有个构造器需要传入Mapper类。也就是说BeanFactory在为该bean创建实例的时候生成的是MapperFactoryBean实例。假设现在有个XxxMapper,BeanFactory会为这个Mapper生成一个BeanDefinition,而这个BeanDefinition的beanClass是MapperFactoryBean,最终创建的实例也是MapperFactoryBean的实例。如果是这样肯定满足不了我们的需求,我们需要的是Mapper的实例,下面我们就来看下BeanFactory是怎么处理MapperFactoryBean实例的。

2 给Mapper生成动态代理

MapperFactoryBean实现了FactoryBean,FactoryBean是一种能生产bean的bean。
在这里插入图片描述
在AbstractBeanFactory.getObjectForBeanInstance()方法里会判断bean实例是否是FactoryBean实例(如果beanName的前缀是以“&”开头会直接返回bean实例),如果是,会调用FactoryBean.getObject()方法获取实例。
在这里插入图片描述
在MapperFactoryBean里是通过sqlSessionTemplate来获取的,在上面已经说到为Mapper生成bean时设置了sqlSessionFactory、sqlSessionTemplate等属性。最终是调用MapperProxyFactory.newInstance()来为每个Mapper生成一个动态代理实例。
在这里插入图片描述

3 总结

以上简要介绍了Mapper初始化的过程,在为Mapper生成bean时将beanClass替换为了MapperFactoryBean。在获取实例的时候会判断bean实例是不是FactoryBean类型的,如果是再调用getObject方法为每个Mapper创建一个动态代理实例。

猜你喜欢

转载自blog.csdn.net/weixin_45497155/article/details/106565709