Sharding JDBC自動配置的原理
與所有starter一樣,shardingsphere-jdbc-core-spring-boot-starter也是通過SPI自動配置的原理實現(xiàn)分庫分表配置加載,spring.factories文件中的自動配置類shardingsphere-jdbc-core-spring-boot-starter功不可沒,他主要是自動創(chuàng)建了模式bean、事務(wù)類型bean和數(shù)據(jù)源bean,配置加載的過程可以歸納如下:
其中,創(chuàng)建數(shù)據(jù)源bean時會根據(jù)不同的模式創(chuàng)建不同的bean,本地模式直接從配置文件中加載,配置中心模式就從配置中心加載。ShardingSphereAutoConfiguration的實現(xiàn)如下:
@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());
}
/**
* 單機(jī)模式:從本地配置中加載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);
}
/**
* 事務(wù)類型掃描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);
}
}
下面以單機(jī)模式出發(fā)點,理一下加載的過程。
@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工廠創(chuàng)建數(shù)據(jù)源
return ShardingSphereDataSourceFactory.createDataSource(databaseName, modeConfig.getIfAvailable(), dataSourceMap, ruleConfigs, props.getProps());
}
通過對源碼的跟蹤,可以發(fā)現(xiàn),ShardingSphereDataSourceFactory.createDataSource創(chuàng)建數(shù)據(jù)源經(jīng)歷了如下的過程
分片規(guī)則加載原理
分片規(guī)則、審計規(guī)則、key生成規(guī)則都是通過SPI的方式加載,自動配置類ShardingSphereAutoConfiguration中創(chuàng)建ShardingSphereDataSource的時候,會加載配置的分片規(guī)則,創(chuàng)建核心配置類ShardingRule,在ShardingRule的創(chuàng)建中會通過SPI的方式加載分片規(guī)則。加載的過程如下:文章來源:http://www.zghlxwxcb.cn/news/detail-693990.html
SPI核心實現(xiàn)類ShardingSphereServiceLoader中會將SPI接口進(jìn)行Map緩存管理,需要時直接獲取。如果Map中不存在,就通過反射的方式新建服務(wù)實例,具體實現(xiàn)源碼如下:文章來源地址http://www.zghlxwxcb.cn/news/detail-693990.html
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<>();
/**
* 注冊服務(wù)實例
*
* @param 服務(wù)接口
*/
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;
}
/**
* 獲取服務(wù)實例
*
* @param 服務(wù)接口
* @param <T> 服務(wù)類型
* @return 服務(wù)實例
*/
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());
}
}
到了這里,關(guān)于Sharding-JDBC分庫分表-自動配置與分片規(guī)則加載原理-3的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!