读写分离+分片的项目中使用三种配置方式来应用ShardingSphere,以下将选择properties的方式读取作为样例。
了解该过程的运行过程后可以有效地帮助快速定位配置文件的问题。

设置断点

定位到SpringBootConfiguration类,该类拥有注解:@AutoConfigureBefore({DataSourceAutoConfiguration.class})是ShardingSphere配置信息读取的入口类,其内部方法如下:
image.png
在概要方法上设置断点,开启配置文件部分的源码阅读。

setEnvironment

断点首先抵达了该方法,其源码如下:

  1. @Override
  2. public final void setEnvironment(final Environment environment) {
  3. dataSourceMap.putAll(DataSourceMapSetter.getDataSourceMap(environment));
  4. }

猜测这步是将所有数据源信息和数据源逻辑名称做出一一对应的关系放入到LinkedHashMap中。

getDataSourceMap

获取并绑定数据源和数据源名称是通过这个方法进行的,其源码如下:

  1. public static Map<String, DataSource> getDataSourceMap(final Environment environment) {
  2. Map<String, DataSource> result = new LinkedHashMap<>();
  3. for (String each : getDataSourceNames(environment)) {
  4. try {
  5. result.put(each, getDataSource(environment, each));
  6. } catch (final ReflectiveOperationException ex) {
  7. throw new ShardingSphereException("Can't find data source type.", ex);
  8. } catch (final NamingException ex) {
  9. throw new ShardingSphereException("Can't find JNDI data source.", ex);
  10. }
  11. }
  12. return result;
  13. }

获取数据源名

数据源名通过getDataSourceNames方法获取:

  1. private static List<String> getDataSourceNames(final Environment environment) {
  2. StandardEnvironment standardEnv = (StandardEnvironment) environment;
  3. standardEnv.setIgnoreUnresolvableNestedPlaceholders(true);
  4. String dataSourceNames = standardEnv.getProperty(PREFIX + DATA_SOURCE_NAME);
  5. if (StringUtils.isEmpty(dataSourceNames)) {
  6. dataSourceNames = standardEnv.getProperty(PREFIX + DATA_SOURCE_NAMES);
  7. }
  8. return new InlineExpressionParser(dataSourceNames).splitAndEvaluate();
  9. }

其首先将environment强转为非Servlet(Web)环境下的标准Environment实现|(StandardEnvironment),然后就开始解析所有spring.shardingsphere.datasource.name/names的消息,解析出名字如下:
image.png
然后将逗号去除返回集合:
image.png

遍历数据源名

断点抵达方法result.put(each, getDataSource(environment, each));

获取数据源

其源码如下:

  1. private static DataSource getDataSource(final Environment environment, final String dataSourceName) throws ReflectiveOperationException, NamingException {
  2. Map<String, Object> dataSourceProps = PropertyUtil.handle(environment, String.join("", PREFIX, dataSourceName), Map.class);
  3. Preconditions.checkState(!dataSourceProps.isEmpty(), String.format("Wrong datasource [%s] properties.", dataSourceName));
  4. if (dataSourceProps.containsKey(JNDI_NAME)) {
  5. return getJNDIDataSource(dataSourceProps.get(JNDI_NAME).toString());
  6. }
  7. DataSource result = DataSourceUtil.getDataSource(dataSourceProps.get(DATA_SOURCE_TYPE).toString(), dataSourceProps);
  8. DataSourcePropertiesSetterHolder.getDataSourcePropertiesSetterByType(dataSourceProps.get(DATA_SOURCE_TYPE).toString()).ifPresent(
  9. propsSetter -> propsSetter.propertiesSet(environment, PREFIX, dataSourceName, result));
  10. return result;
  11. }

这部分的第二行代码用来获取数据源信息:
image.png

完成绑定

绑定之后获得result
image.png
最终赋值给datasourceMap:
image.png

shardingTransactionTypeScanner

  1. @Bean
  2. public ShardingTransactionTypeScanner shardingTransactionTypeScanner() {
  3. return new ShardingTransactionTypeScanner();
  4. }

这里来创建了一个事务类型的扫描器,事务不是现在的重点,暂时跳过。

创建逻辑数据源Bean

该部分源码如下:

  1. @Bean
  2. @Autowired(required = false)
  3. public DataSource shardingSphereDataSource(final ObjectProvider<List<RuleConfiguration>> rules) throws SQLException {
  4. Collection<RuleConfiguration> ruleConfigurations = Optional.ofNullable(rules.getIfAvailable()).orElse(Collections.emptyList());
  5. return ShardingSphereDataSourceFactory.createDataSource(dataSourceMap, ruleConfigurations, props.getProps());
  6. }

这里的第一行把所有的策略模式和分片、读写分离全部读入了RuleConfiguration:
image.png
获得了各种逻辑信息以后就可以配置逻辑数据源了。

createDataSource

  1. public static DataSource createDataSource(final Map<String, DataSource> dataSourceMap, final Collection<RuleConfiguration> configurations, final Properties props) throws SQLException {
  2. return new ShardingSphereDataSource(dataSourceMap, configurations, props);
  3. }

ShardingSphereDataSource:

  1. public ShardingSphereDataSource(final Map<String, DataSource> dataSourceMap, final Collection<RuleConfiguration> configurations, final Properties props) throws SQLException {
  2. metaDataContexts = new MetaDataContextsBuilder(
  3. Collections.singletonMap(DefaultSchema.LOGIC_NAME, dataSourceMap), Collections.singletonMap(DefaultSchema.LOGIC_NAME, configurations), props).build();
  4. String xaTransactionMangerType = metaDataContexts.getProps().getValue(ConfigurationPropertyKey.XA_TRANSACTION_MANAGER_TYPE);
  5. transactionContexts = createTransactionContexts(metaDataContexts.getDefaultMetaData().getResource().getDatabaseType(), dataSourceMap, xaTransactionMangerType);
  6. LockContext.init(LockStrategyType.STANDARD);
  7. }

将各种信息赋值后完成了ShardingSphere的配置文件读取且初始化工作。