【源码】Sharding-JDBC源码分析之ContextManager创建中mode分片配置信息的持久化存储的原理

Sharding-JDBC系列

1、Sharding-JDBC分库分表的基本使用

2、Sharding-JDBC分库分表之SpringBoot分片策略

3、Sharding-JDBC分库分表之SpringBoot主从配置

4、SpringBoot集成Sharding-JDBC-5.3.0分库分表

5、SpringBoot集成Sharding-JDBC-5.3.0实现按月动态建表分表

6、【源码】Sharding-JDBC源码分析之JDBC

7、【源码】Sharding-JDBC源码分析之SPI机制

8、【源码】Sharding-JDBC源码分析之Yaml分片配置文件解析原理

9、【源码】Sharding-JDBC源码分析之Yaml分片配置原理(一)

10、【源码】Sharding-JDBC源码分析之Yaml分片配置原理(二)

11、【源码】Sharding-JDBC源码分析之Yaml分片配置转换原理

12、【源码】Sharding-JDBC源码分析之ShardingSphereDataSource的创建原理

13、【源码】Sharding-JDBC源码分析之ContextManager创建中mode分片配置信息的持久化存储的原理

前言

【源码】Sharding-JDBC源码分析之ShardingSphereDataSource的创建原理-CSDN博客博文的3.1.2中介绍了ContextManager的创建,本文从源码角度分享一下ContextManager的创建过程中,通过配置的mode,进行配置信息的持久化存储原理。

ContextManagerBuilder

ContextManager是通过ContextManagerBuilder.build()方法进行创建的。ContextManagerBuilder是一个接口类,只有build()一个接口方法。有两个实现类,分别为ClusterContextManagerBuilder和StandaloneContextManagerBuilder,分别对应集群和单机两种模式。

在ShardingSphereDataSource的createContextManager()方法中,会根据配置的mode的类型(Standalone和Cluster),通过SPI获取ContextManagerBuilder。默认是Standalone,即StandaloneContextManagerBuilder,本文以StandaloneContextManagerBuilder为例。

StandaloneContextManagerBuilder

StandaloneContextManagerBuilder的源码如下:

java 复制代码
package org.apache.shardingsphere.mode.manager.standalone;

/**
 * 单机上下文管理创建者。持久化配置信息到H2或Mysql
 */
public final class StandaloneContextManagerBuilder implements ContextManagerBuilder {
    
    @Override
    public ContextManager build(final ContextManagerBuilderParameter param) throws SQLException {
        // 获取配置的元数据持久化信息
        PersistRepositoryConfiguration repositoryConfig = param.getModeConfiguration().getRepository();
        // 获取持久化接口对象,默认为JDBCRepository对象
        StandalonePersistRepository repository = null == repositoryConfig
                ? RequiredSPIRegistry.getRegisteredService(StandalonePersistRepository.class)
                : TypedSPIRegistry.getRegisteredService(StandalonePersistRepository.class, repositoryConfig.getType(), repositoryConfig.getProps());
        // 新建元数据持久化service类
        MetaDataPersistService persistService = new MetaDataPersistService(repository);
        // 持久化配置信息,默认保存到h2数据库中
        persistConfigurations(persistService, param);
        InstanceContext instanceContext = buildInstanceContext(param);
        // 监听,处理Standalone的订阅者
        new ProcessStandaloneSubscriber(instanceContext.getEventBusContext());
        // 创建MetaDataContexts,创建ShardingSphereDatabase,保存到MetaDataContexts中
        MetaDataContexts metaDataContexts = MetaDataContextsFactory.create(persistService, param, instanceContext);
        ContextManager result = new ContextManager(metaDataContexts, instanceContext);
        setContextManagerAware(result);
        return result;
    }

    /**
     * 持久化配置信息
     */
    private void persistConfigurations(final MetaDataPersistService persistService, final ContextManagerBuilderParameter param) {
        if (!param.isEmpty()) {
            persistService.persistConfigurations(param.getDatabaseConfigs(), param.getGlobalRuleConfigs(), param.getProps());
        }
    }

    /**
     * 创建InstanceContext。创建StandaloneModeContextManager、GlobalLockContext,传入InstanceContext构造器
     */
    private InstanceContext buildInstanceContext(final ContextManagerBuilderParameter param) {
        return new InstanceContext(new ComputeNodeInstance(param.getInstanceMetaData()),
                new StandaloneWorkerIdGenerator(), param.getModeConfiguration(), new StandaloneModeContextManager(), new GlobalLockContext(null), new EventBusContext());
    }

    /**
     * 为StandaloneModeContextManager对象设置ContextManager
     * @param contextManager
     */
    private void setContextManagerAware(final ContextManager contextManager) {
        ((StandaloneModeContextManager) contextManager.getInstanceContext().getModeContextManager()).setContextManagerAware(contextManager);
    }
    
    @Override
    public String getType() {
        return "Standalone";
    }
    
    @Override
    public boolean isDefault() {
        return true;
    }
}

build()方法执行如下:

1)通过mode的配置信息,获取对应的持久化配置对象,此处为StandalonePersistRepositoryConfiguration对象;

StandalonePersistRepositoryConfiguration记录对应的持久化类型(在单机中,为JDBC)及对应属性(有provider、jdbc_url、username、password)。其中provider为对应的持久化库,如H2、MySQL等。

2)获取持久化接口对象,为JDBCRepository对象;

3)创建元数据持久化service类,MetaDataPersistService对象;

该对象保存了数据库、数据库规则、全局规则、属性等对应的持久化存储Service对象,对应的Service持久化存储对象提供了保存对应配置信息的接口。

4)执行persistConfigurations()方法,调用MetaDataPersistService,持久化存储配置信息;

5)创建InstanceContext;

创建StandaloneModeContextManager、GlobalLockContext,传入InstanceContext构造器。

6)添加监听,处理Standalone模式的订阅者;

7)创建MetaDataContexts,创建ShardingSphereDatabase,保存到MetaDataContexts中;

8)创建ContextManager对象;

9)将ContextManager对象赋值给StandaloneModeContextManager;

10)返回创建的ContextManager对象;

JDBCRepository

JDBCRepository的源码如下:

java 复制代码
package org.apache.shardingsphere.mode.repository.standalone.jdbc;

/**
 * JDBC存储库。用于存储属性配置信息
 */
@Slf4j
public final class JDBCRepository implements StandalonePersistRepository {
    
    private static final String SEPARATOR = "/";
    
    private static final String H2_FILE_MODE_KEY = "file:";

    // JDBC存储库提供者。实现类有H2JDBCRepositoryProvider、MySQLJDBCRepositoryProvider和JDBCRepositoryProviderFixture。
    // 提供固定的表repository的创建、删除、插入、查询
    private JDBCRepositoryProvider provider;
    
    private HikariDataSource hikariDataSource;
    
    @SneakyThrows(SQLException.class)
    @Override
    public void init(final Properties props) {
        // JDBC存储库属性。如果构造方法中传入的props没有值,则默认使用H2数据库保存
        JDBCRepositoryProperties jdbcRepositoryProps = new JDBCRepositoryProperties(props);
        // 创建JDBC存储库的数据源
        hikariDataSource = new HikariDataSource();
        String jdbcUrl = jdbcRepositoryProps.getValue(JDBCRepositoryPropertyKey.JDBC_URL);
        hikariDataSource.setJdbcUrl(jdbcUrl);
        hikariDataSource.setUsername(jdbcRepositoryProps.getValue(JDBCRepositoryPropertyKey.USERNAME));
        hikariDataSource.setPassword(jdbcRepositoryProps.getValue(JDBCRepositoryPropertyKey.PASSWORD));
        try (
                // 通过数据源,默认创建一个H2的数据库连接
                Connection connection = hikariDataSource.getConnection();
                Statement statement = connection.createStatement()) {
            // 获取类型
            String type = jdbcRepositoryProps.getValue(JDBCRepositoryPropertyKey.PROVIDER);
            // 获取对应类型的JDBCRepository提供者
            provider = null == type ? RequiredSPIRegistry.getRegisteredService(JDBCRepositoryProvider.class) : TypedSPIRegistry.getRegisteredService(JDBCRepositoryProvider.class, type);
            // 创建对应的存储库的表。表名:repository
            if (!jdbcUrl.contains(H2_FILE_MODE_KEY)) {
                statement.execute(provider.dropTableSQL());
            }
            statement.execute(provider.createTableSQL());
        }
    }

    /**
     * 获取某个key的配置信息,key的值如:props等
     * @return
     */
    @Override
    public String getDirectly(final String key) {
        try (
                Connection connection = hikariDataSource.getConnection();
                PreparedStatement preparedStatement = connection.prepareStatement(provider.selectByKeySQL())) {
            preparedStatement.setString(1, key);
            try (ResultSet resultSet = preparedStatement.executeQuery()) {
                if (resultSet.next()) {
                    return resultSet.getString("value");
                }
            }
        } catch (final SQLException ex) {
            log.error("Get {} data by key: {} failed", getType(), key, ex);
        }
        return "";
    }

    /**
     * 获取某个key的子key
     * @return
     */
    @Override
    public List<String> getChildrenKeys(final String key) {
        try (
                Connection connection = hikariDataSource.getConnection();
                PreparedStatement preparedStatement = connection.prepareStatement(provider.selectByParentKeySQL())) {
            preparedStatement.setString(1, key);
            try (ResultSet resultSet = preparedStatement.executeQuery()) {
                List<String> resultChildren = new LinkedList<>();
                while (resultSet.next()) {
                    String childrenKey = resultSet.getString("key");
                    if (Strings.isNullOrEmpty(childrenKey)) {
                        continue;
                    }
                    int lastIndexOf = childrenKey.lastIndexOf(SEPARATOR);
                    resultChildren.add(childrenKey.substring(lastIndexOf + 1));
                }
                return new ArrayList<>(resultChildren);
            }
        } catch (final SQLException ex) {
            log.error("Get children {} data by key: {} failed", getType(), key, ex);
        }
        return Collections.emptyList();
    }
    
    @Override
    public boolean isExisted(final String key) {
        return !Strings.isNullOrEmpty(getDirectly(key));
    }

    /**
     * 持久化保存
     * @param key key of data
     * @param value value of data
     */
    @Override
    public void persist(final String key, final String value) {
        try {
            if (isExisted(key)) {
                update(key, value);
                return;
            }
            String tempPrefix = "";
            String parent = SEPARATOR;
            String[] paths = Arrays.stream(key.split(SEPARATOR)).filter(each -> !Strings.isNullOrEmpty(each)).toArray(String[]::new);
            // Create key level directory recursively.
            for (int i = 0; i < paths.length - 1; i++) {
                String tempKey = tempPrefix + SEPARATOR + paths[i];
                String tempKeyVal = getDirectly(tempKey);
                if (Strings.isNullOrEmpty(tempKeyVal)) {
                    if (i != 0) {
                        parent = tempPrefix;
                    }
                    insert(tempKey, "", parent);
                }
                tempPrefix = tempKey;
                parent = tempKey;
            }
            insert(key, value, parent);
        } catch (final SQLException ex) {
            log.error("Persist {} data to key: {} failed", getType(), key, ex);
        }
    }
    
    private void insert(final String key, final String value, final String parent) throws SQLException {
        try (
                Connection connection = hikariDataSource.getConnection();
                PreparedStatement preparedStatement = connection.prepareStatement(provider.insertSQL())) {
            preparedStatement.setString(1, UUID.randomUUID().toString());
            preparedStatement.setString(2, key);
            preparedStatement.setString(3, value);
            preparedStatement.setString(4, parent);
            preparedStatement.executeUpdate();
        }
    }
    
    @Override
    public void update(final String key, final String value) {
        try (
                Connection connection = hikariDataSource.getConnection();
                PreparedStatement preparedStatement = connection.prepareStatement(provider.updateSQL())) {
            preparedStatement.setString(1, value);
            preparedStatement.setString(2, key);
            preparedStatement.executeUpdate();
        } catch (final SQLException ex) {
            log.error("Update {} data to key: {} failed", getType(), key, ex);
        }
    }
    
    @Override
    public void delete(final String key) {
        try (
                Connection connection = hikariDataSource.getConnection();
                PreparedStatement preparedStatement = connection.prepareStatement(provider.deleteSQL())) {
            preparedStatement.setString(1, key);
            preparedStatement.executeUpdate();
        } catch (final SQLException ex) {
            log.error("Delete {} data by key: {} failed", getType(), key, ex);
        }
    }
    
    @Override
    public void close() {
        hikariDataSource.close();
    }
    
    @Override
    public String getType() {
        return "JDBC";
    }
}

4.1 构造方法

构造方法主要执行如下:

1)创建一个JDBCRepositoryProperties对象,传入配置的props;

JDBCRepositoryProperties解析props,将配置的信息按照JDBCRepositoryPropertyKey枚举类中配置的key,获取props中对应的key的值。如果对应的key在props中没有配置,则使用JDBCRepositoryPropertyKey枚举的默认值,采用H2持久化存储。

JDBCRepositoryPropertyKey的源码如下:

java 复制代码
package org.apache.shardingsphere.mode.repository.standalone.jdbc.props;

/**
 * JDBC存储库的属性key。枚举类。默认为H2
 */
@RequiredArgsConstructor
@Getter
public enum JDBCRepositoryPropertyKey implements TypedPropertyKey {
    
    PROVIDER("provider", "H2", String.class),
    
    JDBC_URL("jdbc_url", "jdbc:h2:mem:config;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MYSQL", String.class),
    
    USERNAME("username", "sa", String.class),
    
    PASSWORD("password", "", String.class);
    
    private final String key;
    
    private final String defaultValue;
    
    private final Class<?> type;
}

2)创建HikariDataSource对象,通过JDBCRepositoryProperties中的信息设置HikariDataSource对象的jdbcUrl、username、password;

3)通过HikariDataSource获取一个Connection连接和Statement对象;

4)通过配置的provider,采用SPI获取对应的JDBCRepositoryProvider;

JDBCRepositoryProvider是一个接口,不同的provider有不同的实现,如针对MySQL的MySQLJDBCRepositoryProvider、针对H2的H2JDBCRepositoryProvider。在实现类中,提供了持久化存储配置信息的表的维护、表数据的维护的SQL语句。以下以MySQLJDBCRepositoryProvider为例。

MySQLJDBCRepositoryProvider的源码如下:

java 复制代码
package org.apache.shardingsphere.mode.repository.standalone.jdbc.mysql;

/**
 * MySQL持久化提供器。定义了表、表数据维护的SQL语句。
 */
public final class MySQLJDBCRepositoryProvider implements JDBCRepositoryProvider {
    
    @Override
    public String dropTableSQL() {
        return "DROP TABLE IF EXISTS `repository`";
    }
    
    @Override
    public String createTableSQL() {
        return "CREATE TABLE IF NOT EXISTS `repository`(id varchar(36) PRIMARY KEY, `key` TEXT, `value` TEXT, parent TEXT)";
    }
    
    @Override
    public String selectByKeySQL() {
        return "SELECT `value` FROM `repository` WHERE `key` = ?";
    }
    
    @Override
    public String selectByParentKeySQL() {
        return "SELECT `key` FROM `repository` WHERE parent = ? ORDER BY `key` ASC";
    }
    
    @Override
    public String insertSQL() {
        return "INSERT INTO `repository` VALUES(?, ?, ?, ?)";
    }
    
    @Override
    public String updateSQL() {
        return "UPDATE `repository` SET `value` = ? WHERE `key` = ?";
    }
    
    @Override
    public String deleteSQL() {
        return "DELETE FROM `repository` WHERE `key` = ?";
    }
    
    @Override
    public String getType() {
        return "MySQL";
    }
}

代码比较简单,定义了repository表的创建、删除,以及repository表的增删改查操作的SQL语句。

5)通过JDBCRepositoryProvider对象获取创建表的SQL语句,通过Statement执行SQL语句,创建表;

4.2 persist()持久化方法

persist()配置信息持久化方法主要执行如下:

1)解析key的路径;

2)遍历key的路径,执行insert()方法,按路径、父路径、值,将信息持久化到表中;

在insert()方法中,通过4.1中的JDBCRepositoryProvider,获取插入语句的SQL。再通过HikariDataSource获取Connection,执行SQL语句;

3)按key和value,执行insert()插入配置的信息;

4.3 其他方法

在JDBCRepository类中,还提供了修改update()、删除delete()、查询getDirectly()及查询子目录getChildrenKeys()方法。

MetaDataPersistService

MetaDataPersistService元数据持久化Service类,针对不同的配置信息,提供了不同的持久化Service,源码如下:

java 复制代码
package org.apache.shardingsphere.mode.metadata.persist;

/**
 * 元数据持久化service类。
 */
@Getter
public final class MetaDataPersistService {

    // 持久存储库。存储元数据的持久化接口。可以将元数据存储在H2文件、数据库、nacos、zookeeper、etcd等中。如JDBCRepository
    private final PersistRepository repository;

    // 数据源配置信息持久化的Service
    private final DataSourcePersistService dataSourceService;

    // 数据库配置信息持久化的Service
    private final DatabaseMetaDataPersistService databaseMetaDataService;

    // 数据库规则配置信息持久化的Service
    private final DatabaseRulePersistService databaseRulePersistService;

    // 数据库信息配置信息持久化的Service
    private final GlobalRulePersistService globalRuleService;

    // 属性持久化的Service类
    private final PropertiesPersistService propsService;

    // 元数据版本持久化的Service
    private final MetaDataVersionPersistService metaDataVersionPersistService;

    // ShardingSphere数据的持久化Service
    private final ShardingSphereDataPersistService shardingSphereDataPersistService;
    
    public MetaDataPersistService(final PersistRepository repository) {
        this.repository = repository;
        dataSourceService = new DataSourcePersistService(repository);
        databaseMetaDataService = new DatabaseMetaDataPersistService(repository);
        databaseRulePersistService = new DatabaseRulePersistService(repository);
        globalRuleService = new GlobalRulePersistService(repository);
        propsService = new PropertiesPersistService(repository);
        metaDataVersionPersistService = new MetaDataVersionPersistService(repository);
        shardingSphereDataPersistService = new ShardingSphereDataPersistService(repository);
    }

    /**
     * 持久化配置信息。根据配置类型,使用对应的Service,持久化配置信息
     */
    public void persistConfigurations(final Map<String, ? extends DatabaseConfiguration> databaseConfigs,
                                      final Collection<RuleConfiguration> globalRuleConfigs, final Properties props) {
        // 持久化
        globalRuleService.conditionalPersist(globalRuleConfigs);
        propsService.conditionalPersist(props);
        for (Entry<String, ? extends DatabaseConfiguration> entry : databaseConfigs.entrySet()) {
            String databaseName = entry.getKey();
            // 获取满足对应DataSource配置的属性信息
            Map<String, DataSourceProperties> dataSourcePropertiesMap = getDataSourcePropertiesMap(entry.getValue().getDataSources());
            if (dataSourcePropertiesMap.isEmpty() && entry.getValue().getRuleConfigurations().isEmpty()) {
                databaseMetaDataService.addDatabase(databaseName);
            } else {
                // 持久化DataSource配置的属性信息
                dataSourceService.conditionalPersist(databaseName, getDataSourcePropertiesMap(entry.getValue().getDataSources()));
                databaseRulePersistService.conditionalPersist(databaseName, entry.getValue().getRuleConfigurations());
            }
        }
    }

    /**
     * 获取满足对应DataSource配置的属性信息
     */
    private Map<String, DataSourceProperties> getDataSourcePropertiesMap(final Map<String, DataSource> dataSourceMap) {
        Map<String, DataSourceProperties> result = new LinkedHashMap<>(dataSourceMap.size(), 1);
        for (Entry<String, DataSource> entry : dataSourceMap.entrySet()) {
            result.put(entry.getKey(), DataSourcePropertiesCreator.create(entry.getValue()));
        }
        return result;
    }
    
    /**
     * 获取有效的数据源
     */
    public Map<String, DataSource> getEffectiveDataSources(final String databaseName, final Map<String, ? extends DatabaseConfiguration> databaseConfigs) {
        // 从数据库(H2或Mysql)表中获取对应逻辑数据库名的yaml配置信息,转化成DataSourceProperties
        Map<String, DataSourceProperties> persistedDataPropsMap = dataSourceService.load(databaseName);
        return databaseConfigs.containsKey(databaseName)
                ? mergeEffectiveDataSources(persistedDataPropsMap, databaseConfigs.get(databaseName).getDataSources())
                : DataSourcePoolCreator.create(persistedDataPropsMap);
    }

    /**
     * 合并有效的数据库信息
     */
    private Map<String, DataSource> mergeEffectiveDataSources(final Map<String, DataSourceProperties> persistedDataSourcePropsMap, final Map<String, DataSource> localConfiguredDataSources) {
        Map<String, DataSource> result = new LinkedHashMap<>(persistedDataSourcePropsMap.size(), 1);
        for (Entry<String, DataSourceProperties> entry : persistedDataSourcePropsMap.entrySet()) {
            // 获取配置的数据源名称,如order_ds
            String dataSourceName = entry.getKey();
            // 获取数据源配置的信息,如:url、username、password
            DataSourceProperties persistedDataSourceProps = entry.getValue();
            DataSource localConfiguredDataSource = localConfiguredDataSources.get(dataSourceName);
            if (null == localConfiguredDataSource) {
                // 为空的话,直接将datasource中的配置信息转化为DataSourceProperties,加入到result中
                result.put(dataSourceName, DataSourcePoolCreator.create(persistedDataSourceProps));
            } else if (DataSourcePropertiesCreator.create(localConfiguredDataSource).equals(persistedDataSourceProps)) {
                // 将datasource中的配置信息转化为DataSourceProperties,如何和persistedDataSourceProps相同,则加入到result中
                result.put(dataSourceName, localConfiguredDataSource);
            } else {
                // 如果不等,从池中创建一个连接,通过反射创建一个datasource
                result.put(dataSourceName, DataSourcePoolCreator.create(persistedDataSourceProps));
                // 回收旧的datasource
                new DataSourcePoolDestroyer(localConfiguredDataSource).asyncDestroy();
            }
        }
        return result;
    }
}

5.1 构造方法

在构造方法中,针对不同的配置信息,创建对应的持久化存储Service。在Service中,保存了传入的PersistRepository。如JDBCRepository对象。

5.2 persistConfigurations()持久化方法

在该方法中,针对不同的配置信息,调用对应的Service,执行持久化存储。

如全局配置信息的存储,调用globalRuleService的conditionalPersist()方法。

GlobalRulePersistService

全局配置信息GlobalRulePersistService的源码如下:

java 复制代码
package org.apache.shardingsphere.mode.metadata.persist.service.config.global;

/**
 * 全局规则持久化Service。通过调用PersistRepository的persist()方法,持久化配置信息
 */
@RequiredArgsConstructor
public final class GlobalRulePersistService implements GlobalPersistService<Collection<RuleConfiguration>> {

    // 持久化存储器,如JDBCRepository,提供了针对MySQL、H2数据库数据的增删改查接口
    private final PersistRepository repository;
    
    @Override
    public void conditionalPersist(final Collection<RuleConfiguration> globalRuleConfigs) {
        if (!globalRuleConfigs.isEmpty() && !isExisted()) {
            persist(globalRuleConfigs);
        }
    }

    /**
     * 持久化全局规则配置信息到数据库持久化存储库中
     */
    @Override
    public void persist(final Collection<RuleConfiguration> globalRuleConfigs) {
        // 获取全局规则的接口的key,即路径。值为/rules,即在表中存储的key为/rules的,表示全局规则
        // 将配置的RuleConfiguration对象转换为YamlRuleConfiguration对象,通过YamlEngine.marshal()转换为字符串
        repository.persist(GlobalNode.getGlobalRuleNode(), YamlEngine.marshal(new YamlRuleConfigurationSwapperEngine().swapToYamlRuleConfigurations(globalRuleConfigs)));
    }
    
    @Override
    @SuppressWarnings("unchecked")
    public Collection<RuleConfiguration> load() {
        return isExisted()
                ? new YamlRuleConfigurationSwapperEngine().swapToRuleConfigurations(YamlEngine.unmarshal(repository.getDirectly(GlobalNode.getGlobalRuleNode()), Collection.class))
                : Collections.emptyList();
    }
    
    private boolean isExisted() {
        return !Strings.isNullOrEmpty(repository.getDirectly(GlobalNode.getGlobalRuleNode()));
    }

    /**
     * 从持久化存储库中获取全局规则中的审计规则人员信息
     */
    public Collection<ShardingSphereUser> loadUsers() {
        Optional<AuthorityRuleConfiguration> authorityRuleConfig = load().stream().filter(each -> each instanceof AuthorityRuleConfiguration)
                .map(each -> (AuthorityRuleConfiguration) each).findFirst();
        return authorityRuleConfig.isPresent() ? authorityRuleConfig.get().getUsers() : Collections.emptyList();
    }
}

在GlobalRulePersistService中提供的persist、load方法都是通过传入的PersistRepository(如JDBCRepository对象)对象执行对应的方法实现的。

小结

限于篇幅,本篇先分享到这里。以下做一个小结。

ShardingSphere通过ContextManagerBuilder的build()方法创建ContextManager对象。ContextManagerBuilder是一个接口类,只有build()一个接口方法。有两个实现类,分别为ClusterContextManagerBuilder和StandaloneContextManagerBuilder,分别对应集群和单机两种模式。

本篇以Standalone为例,在StandaloneContextManagerBuilder的build()方法中,执行了分片配置信息的持久化存储,流程如下:

1)通过mode的配置信息,获取对应的持久化配置对象。对于Standalone,此处为StandalonePersistRepositoryConfiguration对象;

本篇以Standalone为例,对于Cluster,实现思路类似,只是对应的持久化存储由MySQL、H2换为分布式配置中心中间件,如Nacos、Zookeeper、Etc、Consul等。

2)创建持久化StandalonePersistRepository对象,此处为JDBCRepository对象;

2.1)JDBCRepository根据mode配置中的props的provider(默认为H2),获取对应的JDBCRepositoryProvider。如MySQL的MySQLJDBCRepositoryProvider,其提供了repository表的创建、删除,以及repository表的增删改查操作的SQL语句;

2.2)根据mode配置中的props中的jdbc_url、username、password,创建HikariDataSource对象;

2.3)获取JDBCRepositoryProvider中创建repository表的SQL语句,通过HikariDataSource对象获取连接,执行SQL语句,实现持久化存储库的表的创建;

2.4)提供了repository表的插入、修改、删除方法;

3)创建元数据持久化service类,MetaDataPersistService对象;

3.1)该对象保存了数据库、数据库规则、全局规则、属性等对应的持久化存储Service对象,对应的Service持久化存储对象提供了保存对应配置信息的接口;

3.2)Service类中对应的持久化方法是通过 2)中的JDBCRepository对象,实现了对应配置信息持久化;

3.3)配置项以多路径的方式作为key存储在repository表中;

4)执行persistConfigurations()方法,调用MetaDataPersistService的持久化方法,持久化存储配置信息;

关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨下吧。

相关推荐
JingAi_jia91715 天前
【源码】Sharding-JDBC源码分析之Sql解析的原理
分库分表·sharding-jdbc·1024程序员节·sharding jdbc·antlr·springboot分库分表·sql解析原理·mysqlstatement
JingAi_jia9172 个月前
【源码】Sharding-JDBC源码分析之ContextManager创建中ShardingSphereDatabase的创建原理
database·分库分表·sharding-jdbc·sharding jdbc·springboot分库分表·shardingjdbc源码
JingAi_jia9173 个月前
【源码】Sharding-JDBC源码分析之Yaml分片配置原理(一)
分库分表·sharding-jdbc·sharding jdbc·springboot分库分表·分库分表配置·分库分表配置原理
JingAi_jia9174 个月前
SpringBoot集成Sharding-JDBC-5.3.0实现按月动态建表分表
分库分表·sharding-jdbc·sharding jdbc·springboot分库分表·按月分库分表