原副标题:Spring资源整合MyBatis之下层基本原理
译者 | Vielle
假如老铁们对Spring架构足够多熟识,资源整合MyBatis只不过很难认知,总之这儿假设老铁们也早已熟识了MyBatis架构。
在他们恒定的应用领域合作开发操作过程中,采用MyBatis通常分成如下表所示三个关键步骤:
1.在实用性类上减少MapperScan注释,比如:@MapperScan(basePackages = {“com.test.dao”},annotationClass = Mapper.class);
2.在basePackages选定的产品目录下建立待MyBatis加载的USB文档,比如:
拷贝
@Mapper
public interface TestMapper {
}
3.在Service或是其它地方性采用该Mapper来操作形式资料库。
采用出来是很单纯的,但是不是老铁想过,为何做了那么两个单纯的实用性,那个Mapper就能操作形式资料库了?Lendelin那个Mapper是个USB,假如是无法被建立才对啊!假如你有那个疑点,断定你是个爱思索的好TX。
咱间接步入主轴。Spring要与MyBatis资源整合,单纯而言如果化解如下表所示三个难题:
一、Spring怎样晓得什么样类应该被管理工作?
要让Spring去管理工作Bean的合作开发周期,具体而言须要相关联的类被Spring扫描器到,因此聚合DeanDefinition,接着如前所述BeanDefinition聚合Bean。上面对Spring聚合BeanDefinition的形式做个小归纳:
包涵Component、Configuration、ComponentScan、Import、ImportResource注释的类; Import注释中选定的类、被Bean注释标示的形式所处的类; 同时实现了ImportBeanDefinitionRegistrarUSB,因此在registerBeanDefinitions形式中初始化registry间接注册的类; 同时实现了ImportSelectorUSB,因此在selectImports形式中返回的字符串相关联的类; 间接初始化register形式; 另外Spring还提供了两个扩展,可以让合作开发者自己选定须要被管理工作的类相关联的类型:通过往includeFilters中添加注释类类型。他们分析源码,第一步得找到它的入口,Spring资源整合MyBatis的入口,毫无疑点是MapperScan那个注释,在MapperScan注释上包涵Import(MapperScannerRegistrar.class)注释,Spring资源整合MyBatis正是用了Import和ImportBeanDefinitionRegistrar的形式。他们先通过一张流程图来了解下整体流程,接着再慢慢品。
他们来看MapperScannerRegistrar那个类的继承关系图:
MapperScannerRegistrar是ImportBeanDefinitionRegistrar的同时实现类,Spring会去初始化那个类的registerBeanDefinitions形式添加beanDefinition,那个形式中具体做了些什么呢:
Class则是选定了减少了这种注释类的类须要被Spring进行管理工作,比如减少了Mapper注释的类须要被Spring管理工作。
聚合MapperScannerConfigurer那个类型的beanDefinition,因此把MapperScan注释的实用性信息添加到该beanDefinition的属性集合中。
后续Spring就会如前所述那个MapperScannerConfigurer做一系列文章,看下它的继承关系:
它是BeanDefinitionRegistryPostProcessor的同时实现类,是两个BeanFactory后置处理器,Spring会初始化该类的postProcessBeanDefinitionRegistry形式来添加beanDefinition的操作形式,MapperScannerConfigurer那个类中具体同时实现如下表所示:
它定义了ClassPathMapperScanner那个扫描器器,接着采用那个扫描器器来扫描器类,扫描器什么样类呢?扫描器有Mapper注释的类,看它的关系晓得,它是ClassPathBeanDefinitionScanner的子类,而spring则是采用ClassPathBeanDefinitionScanner来进行扫描器的。
为何ClassPathMapperScanner能够扫描器到带有Mapper注释的类呢?看上面代码,就是通过初始化registerFilters形式来添加includeFilter(实际类型是:TypeFilter),那个就是Spring提供的扩展点,让咱自己来选定须要被扫描器的类,这儿采用的是MappScan注释中annotationClass属性实用性的注释类型,他们这儿实用性了Mapper,所以初始化scan形式开启扫描器后,Spring就会将包涵Mapper注释的类扫描器为BeanDefinition。注意这儿的扫描器能力还是初始化Spring的扫描器来同时实现的,ClassPathMapperScanner并没有修改,只是当扫描器完成后,ClassPathMapperScanner会对扫描器出的BeanDefinition进行重新处理,主要是把原来的BeanClass修改成了MapperFactoryBean.class:
而那个MapperFactoryBean是FactoryBean的同时实现类,老铁们,FactoryBean这种Bean有什么特点?那个可是面试的高发点哦。
做个小小的归纳:Spring扫描器到有Mapper注释的类,聚合BeanDefinition,因此将这一类BeanDefinition的BeanClass的值修改为MapperFactoryBean,也就是说它的类型不再是咱自己编写的MapperUSB了,而是两个FactoryBean,这样Spring就能做妖了。
二、Mapper注释的类是USB
那怎样实例化呢?
到这一步,只不过老铁们也大概清楚了,Spring在实例化Mapper实例时,实际上具体而言会实例化MapperFactoryBean,接着再初始化它的getObject形式。他们晓得在Java里面USB是肯定无法被实例化的,那那个被实例化的对象只能是两个代理对象,所以他们有理由猜想那个getObject形式假如是用来建立代理对象的。要建立代理对象,得从以下三个方面着手:
1.准备工作
这儿Spring准备的是USB类型和建立代理对象的代理工厂。具体怎样准备的呢?来看上述MapperFactoryBean类型的整体继承关系:
它同时实现了InitializingBean,于是可以晓得,在MapperFactoryBean初始化完成后,Spring会初始化它的afterPropertiesSet形式,从而会执行到checkDaoConfig形式:
在该形式中初始化configuration的addMapper形式,那个形式里面到底做了啥?
看出门道了吗?只不过就是采用Mapper的USB类型作为key,MapperProxyFactory做为value,接着添加到mapperRegistry对象的Map集合中,注意那个type同时也是MapperProxyFactory对象的构造参数哦。
2.实例化
上述动作早已准备好了,接下来就假如是建立了。Spring在建立完成MapperFactoryBean对象后,最终会初始化它的getObject形式来获得真实的对象:
getObject形式中,会初始化getMapper形式,该形式中从knowMappers那个Map集合中拿到MapperProxyFactory对象,那个对象不就是他们在准备阶段添加的嘛!它就是用来建立代理对象的工厂。
从上面代码中也不难看出,确实是为咱自己的USB建立了代理对象,而代理类的处理类则是MapperProxy对象,也就是说对所有USB对象的初始化,都会步入MapperProxy的Invoke形式,至此Spring成功对接MyBatis。
译者介绍
Vielle,互联行业从业10余年,先后担任项目总监及架构师。目前专攻技术,喜欢研究技术基本原理。技术全面,主攻java,精通JVM下层机制及Spring全家桶下层架构基本原理,熟练掌握当前主流的中间件、服务网格等技术基本原理。