返回

shardingsphere(5.0.0.beta)元数据上下文

shardingsphere(5.0.0.beta)元数据上下文

Shardingsphere(5.0.0.beta)源码学习-元数据上下文

上下文对象

上下文对象作为读取并解析配置, 承载数据的核心;

spring有ApplicationContext,netty有HandlerContext

向其他中间件一样,在ShardingSphere也十分重要; 后续几乎所有功能比如数据分片、数据加密、SQL 改写,各类扩展都依赖上下文对象存储的数据

image-20210913215827140

标准元数据上下文 StandardMetaDataContexts

核心存储了ShardingSphereMetaData元数据集合,作为重点后面分析

@Getter
public final class StandardMetaDataContexts implements MetaDataContexts {
    
    // 元数据集合
    private final Map<String, ShardingSphereMetaData> metaDataMap;
    
    private final ShardingSphereRuleMetaData globalRuleMetaData;
    // 执行引擎
    private final ExecutorEngine executorEngine;
    //优化引擎上下文工厂
    private final OptimizeContextFactory optimizeContextFactory;
    
    private final ConfigurationProperties props;
    // 状态上下文
    private final StateContext stateContext;
    
    ...
}

治理元数据上下文 StandardMetaDataContexts

其实也是用的标准的StandardMetaDataContexts,治理模块shardingsphere-governance使用该上下文,通过配置中心读取规则配置,

注入到StandardMetaDataContexts中,GovernanceFacade是配置中心的门面模式,目前支持了zookeeper和etcd,其实还可以通过RegistryCenterRepository的spi实现其他的配置中心,比如nacos, apollo,consul等。

public final class GovernanceMetaDataContexts implements MetaDataContexts {
    
    //治理: 配置中心的门面模式
    private final GovernanceFacade governanceFacade;
    
    //还是使用StandardMetaDataContexts  装饰器模式
    private volatile StandardMetaDataContexts metaDataContexts;
    
    private final ShardingSphereLock lock;
    
    ...
}

初始化上下文对象

ShardingSphere中通过

org.apache.shardingsphere.infra.context.metadata.MetaDataContextsBuilder构造器模式,构造

org.apache.shardingsphere.infra.context.metadata.MetaDataContexts

public ShardingSphereDataSource(final Map<String, DataSource> dataSourceMap, final Collection<RuleConfiguration> configurations, final Properties props) throws SQLException {
    // 构建器构造 元数据上下文
    metaDataContexts = new MetaDataContextsBuilder(
            Collections.singletonMap(DefaultSchema.LOGIC_NAME, dataSourceMap), Collections.singletonMap(DefaultSchema.LOGIC_NAME, configurations), props).build();
   // xa事务类型
    String xaTransactionMangerType = metaDataContexts.getProps().getValue(ConfigurationPropertyKey.XA_TRANSACTION_MANAGER_TYPE);
  // 创建事务上下文TransactionContexts//后面学习中细讲,本文不涉及
    transactionContexts = createTransactionContexts(metaDataContexts.getDefaultMetaData().getResource().getDatabaseType(), dataSourceMap, xaTransactionMangerType);
}

MetaDataContextsBuilder.build()构建MetaDataContexts

org.apache.shardingsphere.infra.context.metadata.MetaDataContextsBuilder.build方法

    /**
     * Build meta data contexts.
     * 
     * @exception SQLException SQL exception
     * @return meta data contexts
     */
    public StandardMetaDataContexts build() throws SQLException {
        Map<String, ShardingSphereMetaData> mataDataMap = new HashMap<>(schemaRuleConfigs.size(), 1);
        for (String each : schemaRuleConfigs.keySet()) {
            // buildMetaData构造核心的元数据对象ShardingSphereMetaData,加入到集合中
            mataDataMap.put(each, buildMetaData(each));
        }
        // 返回标准元数据上下文
        return new StandardMetaDataContexts(mataDataMap, buildGlobalSchemaMetaData(mataDataMap), executorEngine, props);
    }

ShardingSphere元数据

ShardingSphere元数据存储以下数据:

1数据源: 元数据资源,

2 规则配置

3 数据库元数据信息,表,字段,索引

// 
@RequiredArgsConstructor
@Getter
public final class ShardingSphereMetaData {
    
    private final String name;
    
    // 数据源 元数据资源
    private final ShardingSphereResource resource;
    
    // 配置规则元数据: 原始配置RuleConfiguration集合  =》  配置解析后的ShardingSphereRule集合
    private final ShardingSphereRuleMetaData ruleMetaData;
    
    // 数据库表元数据:  字段元数据及索引元数据
    private final ShardingSphereSchema schema;
    
    /**
     * Judge whether is completed.
     *
     * @return is completed or not
     */
    public boolean isComplete() {
        return !ruleMetaData.getRules().isEmpty() && !resource.getDataSources().isEmpty();
    }
}

再看如何构建ShardingSphere元数据,buildMetaData方法

 private ShardingSphereMetaData buildMetaData(final String schemaName) throws SQLException {
        Map<String, DataSource> dataSourceMap = dataSources.get(schemaName);
        Collection<RuleConfiguration> ruleConfigs = schemaRuleConfigs.get(schemaName);
        //确定数据库类型
        DatabaseType databaseType = DatabaseTypeRecognizer.getDatabaseType(dataSourceMap.values());
        //a) 通过用户配置的RuleConfiguration 解析出 ShardingSphereRule
        Collection<ShardingSphereRule> rules = ShardingSphereRulesBuilder.buildSchemaRules(schemaName, ruleConfigs, databaseType, dataSourceMap);
        // 构造规则元数据对象ShardingSphereRuleMetaData
        ShardingSphereRuleMetaData ruleMetaData = new ShardingSphereRuleMetaData(ruleConfigs, rules);
        //构造ShardingSphere元数据对象ShardingSphereMetaData  
        //b) 构建数据源的元数据对象 c) 构建数据库的元数据
        return new ShardingSphereMetaData(schemaName, buildResource(databaseType, dataSourceMap), ruleMetaData, buildSchema(databaseType, dataSourceMap, rules));
    }

a) ShardingSphere规则元数据

@RequiredArgsConstructor
@Getter
public final class ShardingSphereRuleMetaData {
    // 用户配置的规则对象集合
    private final Collection<RuleConfiguration> configurations;
    // 解析后的规则集合
    private final Collection<ShardingSphereRule> rules;
}

RuleConfiguration直接对应了用户的yaml, properties等配置

image-20210913214107105

ShardingSphereRule

image-20210913222453670

buildSchemaRules()

 public static Collection<ShardingSphereRule> buildSchemaRules(final String schemaName, final Collection<RuleConfiguration> schemaRuleConfigurations,
                                                                  final DatabaseType databaseType, final Map<String, DataSource> dataSourceMap) {
        Map<RuleConfiguration, SchemaRuleBuilder> builders = OrderedSPIRegistry.getRegisteredServices(schemaRuleConfigurations, SchemaRuleBuilder.class);
        appendDefaultKernelSchemaRuleConfigurationBuilder(builders);
        // SchemaRuleBuilder. build() 构建ShardingSphereRule
        return builders.entrySet().stream().map(entry -> entry.getValue().build(schemaName, dataSourceMap, databaseType, entry.getKey())).collect(Collectors.toList());
    }

SchemaRuleBuilder作为一个规则解析扩展点

image-20210914013607189

b) 再看buildResource,即构建数据源的元数据对象

private ShardingSphereResource buildResource(final DatabaseType databaseType, final Map<String, DataSource> dataSourceMap) throws SQLException {
    //构建数据源的元数据对象
    DataSourcesMetaData dataSourceMetas = new DataSourcesMetaData(databaseType, getDatabaseAccessConfigurationMap(dataSourceMap));
    //缓存下数据源的各类属性 链接,用户名,驱动,各类版本等等的原始信息
    CachedDatabaseMetaData cachedDatabaseMetaData = createCachedDatabaseMetaData(dataSourceMap).orElse(null);
    return new ShardingSphereResource(dataSourceMap, dataSourceMetas, cachedDatabaseMetaData, databaseType);
}

c) 再看如何构建数据库元数据, buildSchema()方法

加载数据库的元数据,但是各个方言版本的元数据不太一样,例如mysql的在information_schema中,针对对不同方言,可以通过DialectTableMetaDataLoader的spi扩展定制各类方言版本的数据库元数据加载。

image-20210914014024075

  • 数据库元数据
public final class ShardingSphereSchema {
    // 表元数据
    private final Map<String, TableMetaData> tables;
    ...
}
  • 数据库表元数据
  // 表元数据
public final class TableMetaData {
    // 组合 列元数据
    private final Map<String, ColumnMetaData> columns;
    // 组合 索引元数据
    private final Map<String, IndexMetaData> indexes;
    ...
}

列元数据

@RequiredArgsConstructor
@Getter
@EqualsAndHashCode
@ToString
public final class ColumnMetaData {
   // 列名
    private final String name;
    // 数据类型
    private final int dataType;
    // 是否主键
    private final boolean primaryKey;
    // 是否自动生成
    private final boolean generated;
    // 是否大小敏感
    private final boolean caseSensitive;
}
public final class IndexMetaData {
    // 索引字段名
    private final String name;
}

buildSchema()方法

    private ShardingSphereSchema buildSchema(final DatabaseType databaseType, final Map<String, DataSource> dataSourceMap, final Collection<ShardingSphereRule> rules) throws SQLException {
        return SchemaBuilder.build(new SchemaBuilderMaterials(databaseType, dataSourceMap, rules, props));
    }
public static ShardingSphereSchema build(final SchemaBuilderMaterials materials) throws SQLException {
        ShardingSphereSchema result = new ShardingSphereSchema();
        // 有规则配置的表的处理 可以通过 RuleBasedTableMetaDataBuilder 的spi扩展解析
        addRuleConfiguredTables(materials, result);
        // 通过找对对应方言数据库的加载器DialectTableMetaDataLoader加载
        appendRemainTables(materials, result);
        return result;
    }

总结

整个加载过程中使用不少设计模式,构造器模式,工厂模式,装饰器,组合等等,spi扩展点也预留不少,仔细研读收获颇丰。

目前的解读只是从大的主线来理解,当然中间还有很多细节需要后续补充。

debug过程中容易走丢,实时记录下路线是个不错的方式:

image-20210914001438627

Built with Hugo
Theme Stack designed by Jimmy
本站访问量:   您是本站第 位访问者