Sharding JDBC自动配置的原理
与所有starter一样,shardingsphere-jdbc-core-spring-boot-starter也是通过SPI自动配置的原理实现分库分表配置加载,spring.factories文件中的自动配置类shardingsphere-jdbc-core-spring-boot-starter功不可没,他主要是自动创建了模式bean、事务类型bean和数据源bean,配置加载的过程可以归纳如下:
其中,创建数据源bean时会根据不同的模式创建不同的bean,本地模式直接从配置文件中加载,配置中心模式就从配置中心加载。ShardingSphereAutoConfiguration的实现如下:
@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);
}
}
下面以单机模式出发点,理一下加载的过程。
@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创建数据源经历了如下的过程
分片规则加载原理
分片规则、审计规则、key生成规则都是通过SPI的方式加载,自动配置类ShardingSphereAutoConfiguration中创建ShardingSphereDataSource的时候,会加载配置的分片规则,创建核心配置类ShardingRule,在ShardingRule的创建中会通过SPI的方式加载分片规则。加载的过程如下:
SPI核心实现类ShardingSphereServiceLoader中会将SPI接口进行Map缓存管理,需要时直接获取。如果Map中不存在,就通过反射的方式新建服务实例,具体实现源码如下:
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());
}
}