前言
本文将实现一个MyBatis的Springboot的Starter包,引用这个Starter包后,仅需要提供少量配置信息,就能够完成MyBatis多数据源的初始化和使用,相较于MyBatis官方的Starter包,扩展了多数据源的使用场景。
Springboot版本:2.7.6
正文
一. 实现思路
要实现Starter包,肯定需要借助Springboot的自动装配机制,所以我们首先需要提供自动装配的配置类。
然后我们需要加载多个数据源的配置并且生成对应的数据源,同时还需要可以根据用户配置的type创建不同的数据源,例如可以支持创建HikariCP,Druid和TomcatJdbc的数据源。
创建出来的数据源需要根据用户的配置,设置给不同的SqlSessionFactory,然后不同的SqlSessionFactory设置给不同的MapperScannerConfigurer,最终实现的效果就是一部分映射接口使用一个数据源,另一部分映射接口使用另一个数据源。
最后,还需要提供一种手段,抑制Springboot原生的数据源加载,这个功能我们可以通过ApplicationContextInitializer这个扩展点来完成。
整体的一个思维导图如下所示。
二. 自动装配实现
由于适配的是Springboot的2.7.x版本,所以需要在resources\META-INF\spring目录下创建org.springframework.boot.autoconfigure.AutoConfiguration.imports文件,且内容如下所示。
com.lee.multidatasource.autoconfig.LeeMultiPersistenceAutoConfiguration
复制代码
上述的LeeMultiPersistenceAutoConfiguration就是完成自动装配的配置类,实现如下。
@AutoConfiguration
@Import({LeeMultiPersistenceConfiguration.class, DataSourceBeanPostProcessor.class,})
public class LeeMultiPersistenceAutoConfiguration {}
复制代码
通过LeeMultiPersistenceAutoConfiguration导入了两个bean,一个是LeeMultiPersistenceConfiguration,用于加载配置以及创建数据源和MyBatis的bean,另一个是DataSourceBeanPostProcessor,用于对LeeMultiPersistenceConfiguration创建的bean做一些后置处理。
上述就是自动装配的实现,主要就是将LeeMultiPersistenceAutoConfiguration注册到容器中,而LeeMultiPersistenceAutoConfiguration也是整个Starter包实现的关键。
三. 配置加载
约定数据源和MyBatis的配置需要遵循如下规则。
lee:
persistence:
dataSourceName1:
datasource:
type: ...
max-lifetime: ...
keep-alive-time: ...
driver-class-name: ...
url: ...
username: ...
password: ...
pool-name: ...
mybatis:
configLocation: ...
basePackage: ...
dataSourceName2:
datasource:
max-lifetime: ...
keep-alive-time: ...
driver-class-name: ...
url: ...
username: ...
password: ...
pool-name: ...
mybatis:
configLocation: ...
basePackage: ...
复制代码
在lee.persistence的下一级的配置,是数据源的名字,可以由用户自定义,这个名字最终会作为数据源的bean在IOC容器中的名字。
在lee.persistence.dataSourceName的下一级的配置,固定是两个配置项,其一是lee.persistence.dataSourceName.datasource,用于设置数据源相关的配置,其二是lee.persistence.dataSourceName.mybatis,用于设置MyBatis相关的配置。
由于数据源的名字和个数都可以由用户自定义,那么很难基于@ConfigurationProperties注解来一步到位的完成上述数据源配置的加载,我们需要基于Environment来自行处理。
下面来看一下用于处理数据源配置的LeeMultiPersistenceConfiguration的类图,如下所示。
LeeMultiPersistenceConfiguration首先实现了EnvironmentAware接口,从而可以拿到Environment对象,其次实现了ImportBeanDefinitionRegistrar接口,从而可以向Spring注册BeanDefinition,那么实际上LeeMultiPersistenceConfiguration做的事情就是加载配置以及向Spring注册数据源和MyBatis相关组件的BeanDefinition。下面看一下LeeMultiPersistenceConfiguration实现的registerBeanDefinitions() 方法。
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
// 加载并解析数据源配置
MultiPersistenceProperties multiPersistenceProperties = parseMultiPersistenceProperties();
List<String> persistenceNames = multiPersistenceProperties.getPersistenceNames();
// 为每个数据源注册BeanDefinition
for (String persistenceName : persistenceNames) {
registerDatasource(registry, persistenceName, multiPersistenceProperties.getDataSourceProperties(persistenceName));
registerSqlSessionFactory(registry, persistenceName, multiPersistenceProperties.getMybatisProperties(persistenceName));
registerMapperScannerConfigurer(registry, persistenceName, multiPersistenceProperties.getMybatisProperties(persistenceName));
}
}
复制代码
本节就先分析一下数据源配置的加载和解析,具体就是LeeMultiPersistenceConfiguration的parseMultiPersistenceProperties() 方法,如下所示。
private MultiPersistenceProperties parseMultiPersistenceProperties() {
MultiPersistenceProperties multiPersistenceProperties = new MultiPersistenceProperties();
// 将数据源相关的配置加载为MultiPersistencePropertiesWrapper
MultiPersistencePropertiesWrapper multiPersistencePropertiesWrapper = parseMultiPersistencePropertiesWrapper();
List<String> persistenceNames = multiPersistencePropertiesWrapper.getPersistenceNames();
// 遍历每一个数据源并拿到这个数据源下数据源相关配置和MyBatis相关配置
for (String persistenceName : persistenceNames) {
DataSourceProperties dataSourceProperties = multiPersistencePropertiesWrapper
.getPersistenceDataSourceProperties(persistenceName);
MybatisExt