Sharding JDBC自动配置的原理
与所有starter一样,shardingsphere-jdbc-core-spring-boot-starter也是通过SPI自动配置的原理实现分库分表配置加载,spring.factories文件中的自动配置类shardingsphere-jdbc-core-spring-boot-starter功不可没,他主要是自动创建了模式bean、事务类型bean和数据源bean,配置加载的过程可以归纳如下:
创建模式bean 创建数据源bean 创建事务类型扫描bean ShardingSphereAutoConfiguration ModeConfiguration ShardingSphereDataSource TransactionTypeScanner
其中,创建数据源bean时会根据不同的模式创建不同的bean,本地模式直接从配置文件中加载,配置中心模式就从配置中心加载。ShardingSphereAutoConfiguration的实现如下:
java
@Configuration
@ComponentScan("org.apache.shardingsphere.spring.boot.converter")
@EnableConfigurationProperties(SpringBootPropertiesConfiguration.class)
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
@RequiredArgsConstructor
public class ShardingSphereAutoConfiguration implements EnvironmentAware {
private String databaseName;
private final SpringBootPropertiesConfiguration props;
private final Map<String, DataSource> dataSourceMap = new LinkedHashMap<>();
/**
* 模式配置
*
* @return mode configuration
*/
@Bean
public ModeConfiguration modeConfiguration() {
return null == props.getMode() ? null : new YamlModeConfigurationSwapper().swapToObject(props.getMode());
}
/**
* 单机模式:从本地配置中加载DataSource
*
* @param rules rules configuration
* @param modeConfig mode configuration
* @return data source bean
* @throws SQLException SQL exception
*/
@Bean
@Conditional(LocalRulesCondition.class)
@Autowired(required = false)
public DataSource shardingSphereDataSource(final ObjectProvider<List<RuleConfiguration>> rules, final ObjectProvider<ModeConfiguration> modeConfig) throws SQLException {
Collection<RuleConfiguration> ruleConfigs = Optional.ofNullable(rules.getIfAvailable()).orElseGet(Collections::emptyList);
return ShardingSphereDataSourceFactory.createDataSource(databaseName, modeConfig.getIfAvailable(), dataSourceMap, ruleConfigs, props.getProps());
}
/**
* 集群模式:从配置中心中加载DataSource
*
* @param modeConfig mode configuration
* @return data source bean
* @throws SQLException SQL exception
*/
@Bean
@ConditionalOnMissingBean(DataSource.class)
public DataSource dataSource(final ModeConfiguration modeConfig) throws SQLException {
return !dataSourceMap.isEmpty() ? ShardingSphereDataSourceFactory.createDataSource(databaseName, modeConfig, dataSourceMap, Collections.emptyList(), props.getProps())
: ShardingSphereDataSourceFactory.createDataSource(databaseName, modeConfig);
}
/**
* 事务类型扫描bean
*
* @return transaction type scanner
*/
@Bean
public TransactionTypeScanner transactionTypeScanner() {
return new TransactionTypeScanner();
}
@Override
public final void setEnvironment(final Environment environment) {
dataSourceMap.putAll(DataSourceMapSetter.getDataSourceMap(environment));
databaseName = DatabaseNameSetter.getDatabaseName(environment);
}
}
下面以单机模式出发点,理一下加载的过程。
java
@Bean
@Conditional(LocalRulesCondition.class)
@Autowired(required = false)
public DataSource shardingSphereDataSource(final ObjectProvider<List<RuleConfiguration>> rules, final ObjectProvider<ModeConfiguration> modeConfig) throws SQLException {
Collection<RuleConfiguration> ruleConfigs = Optional.ofNullable(rules.getIfAvailable()).orElseGet(Collections::emptyList);
// 通过ShardingSphereDataSourceFactory工厂创建数据源
return ShardingSphereDataSourceFactory.createDataSource(databaseName, modeConfig.getIfAvailable(), dataSourceMap, ruleConfigs, props.getProps());
}
通过对源码的跟踪,可以发现,ShardingSphereDataSourceFactory.createDataSource创建数据源经历了如下的过程
创建数据源bean new 创建上下文管理器 创建JDBC上下文 创建InstanceMetaData 根据mode调用 创建元数据上下文 创建数据库连接元数据 调用 加载分片规则 new ShardingSphereAutoConfiguration ShardingSphereDataSourceFactory.createDataSource ShardingSphereDataSource ShardingSphereDataSource.createContextManager JDBCContext InstanceMetaDataBuilderFactory.create StandaloneContextManagerBuilder.build MetaDataContextsFactory.create ShardingSphereDatabasesFactory.create ShardingSphereDatabase.create DatabaseRulesBuilder.build ShardingSphereDatabase
分片规则加载原理
分片规则、审计规则、key生成规则都是通过SPI的方式加载,自动配置类ShardingSphereAutoConfiguration中创建ShardingSphereDataSource的时候,会加载配置的分片规则,创建核心配置类ShardingRule,在ShardingRule的创建中会通过SPI的方式加载分片规则。加载的过程如下:
创建数据源bean 查询实例 通过SPI Class获取服务实例 Y:创建新的service实例 N:Map中获取service单例 创建分片规则 创建分片规则 创建核心分库分表规则 分片规则 Key生成规则 审计规则 通过工厂创建分片算法 获取注册的service SPI方式获取service 通过工厂创建key生成算法 通过工厂创建审计算法 ShardingSphereAutoConfiguration ShardingSphereDataSource 一系列加载... DatabaseRulesBuilder.build OrderedSPIRegistry.getRegisteredServices ShardingSphereServiceLoader.getServiceInstances(spiClass) 带@SingletonSPI注解? service.getClass().getDeclaredConstructor().newInstance() SERVICES.getOrDefault(serviceInterface, Collections.emptyList()) ShardingRuleBuilder.build new ShardingRule ShardingAlgorithmFactory.newInstance KeyGenerateAlgorithmFactory.newInstance ShardingAuditAlgorithmFactory.newInstance ShardingSphereAlgorithmFactory.createAlgorithm TypedSPIRegistry.getRegisteredService ShardingSphereServiceLoader.getServiceInstances(spiClass)
SPI核心实现类ShardingSphereServiceLoader中会将SPI接口进行Map缓存管理,需要时直接获取。如果Map中不存在,就通过反射的方式新建服务实例,具体实现源码如下:
java
public final class ShardingSphereServiceLoader {
// 缓存service实例,
// 缓存的Key,如:
// org.apache.shardingsphere.sharding.spi.ShardingAlgorithm
// org.apache.shardingsphere.sharding.spi.KeyGenerateAlgorithm
// org.apache.shardingsphere.transaction.spi.ShardingSphereTransactionManager
private static final Map<Class<?>, Collection<Object>> SERVICES = new ConcurrentHashMap<>();
/**
* 注册服务实例
*
* @param 服务接口
*/
public static void register(final Class<?> serviceInterface) {
if (!SERVICES.containsKey(serviceInterface)) {
SERVICES.put(serviceInterface, load(serviceInterface));
}
}
private static <T> Collection<Object> load(final Class<T> serviceInterface) {
Collection<Object> result = new LinkedList<>();
for (T each : ServiceLoader.load(serviceInterface)) {
result.add(each);
}
return result;
}
/**
* 获取服务实例
*
* @param 服务接口
* @param <T> 服务类型
* @return 服务实例
*/
public static <T> Collection<T> getServiceInstances(final Class<T> serviceInterface) {
return null == serviceInterface.getAnnotation(SingletonSPI.class) ? createNewServiceInstances(serviceInterface) : getSingletonServiceInstances(serviceInterface);
}
@SneakyThrows(ReflectiveOperationException.class)
@SuppressWarnings("unchecked")
private static <T> Collection<T> createNewServiceInstances(final Class<T> serviceInterface) {
if (!SERVICES.containsKey(serviceInterface)) {
return Collections.emptyList();
}
Collection<Object> services = SERVICES.get(serviceInterface);
if (services.isEmpty()) {
return Collections.emptyList();
}
Collection<T> result = new LinkedList<>();
for (Object each : services) {
// 通过反射新建实例
result.add((T) each.getClass().getDeclaredConstructor().newInstance());
}
return result;
}
@SuppressWarnings("unchecked")
private static <T> Collection<T> getSingletonServiceInstances(final Class<T> serviceInterface) {
return (Collection<T>) SERVICES.getOrDefault(serviceInterface, Collections.emptyList());
}
}