系统集成即ShardingSphere 和 Spring 框架的集成。

ShardingSphere 实现两种系统集成机制

  • 命名空间(namespace)机制,通过扩展 Spring Schema 来实现与 Spring 框架的集成
  • 编写自定义 starter 组件完成与 Spring Boot 的集成

1 基于命名空间集成 Spring

扩展性角度,基于 XML Schema 的扩展机制常见而实用。Spring允许我们自定义 XML 结构,并且用自己的 Bean 解析器解析。通过对 Spring Schema 的扩展,ShardingSphere 可以完成与 Spring 框架的有效集成。

1.1 基于命名空间集成 Spring 的通用开发流程

基于命名空间机制实现与 Spring 的整合,开发通常采用固定流程:

  • 编写业务对象
  • 编写XSD文件
  • 编写BeanDefinitionParser实现类
  • 编写NamespaceHandler实现类
  • 编写 spring.handlers 和 spring.schemas 配置文件

2 ShardingSphere 集成 Spring

ShardingSphere存在两个“spring-namespace”结尾的代码工程:

  • sharding-jdbc-spring-namespace
  • sharding-jdbc-orchestration-spring-namespace
    关注编排治理相关功能的集成,相对简单。命名空间机制的实现过程也基本一致,因此,以 sharding-jdbc-spring-namespace 为例讨论。

sharding-jdbc-spring-namespace又包含:

  • 普通分片
  • 读写分离
  • 数据脱敏

三块核心功能的集成内容,实现也都是采用类似方式,因此也不重复说明,以普通分片为例介绍。

专门用于与 Spring 进行集成的

SpringShardingDataSource 类,即业务对象类:

public class SpringShardingDataSource extends ShardingDataSource {
     
     public SpringShardingDataSource(final Map<String, DataSource> dataSourceMap, final ShardingRuleConfiguration shardingRuleConfiguration, final Properties props) throws SQLException {
         super(dataSourceMap, new ShardingRule(shardingRuleConfiguration, dataSourceMap.keySet()), props);
     }
 }

只是对 ShardingDataSource 的简单封装,无任何实际操作。

配置项标签的定义类

简单的工具类,定义标签的名称。ShardingSphere的这些类都以“BeanDefinitionParserTag”结尾,如ShardingDataSourceBeanDefinitionParserTag:

public final class ShardingDataSourceBeanDefinitionParserTag {
     public static final String ROOT_TAG = "data-source";
     public static final String SHARDING_RULE_CONFIG_TAG = sharding-rule";
     public static final String PROPS_TAG = "props";
   public static final String DATA_SOURCE_NAMES_TAG = "data-source-names";
   public static final String DEFAULT_DATA_SOURCE_NAME_TAG = "default-data-source-name";
     public static final String TABLE_RULES_TAG = "table-rules"; 
     …
 }

定义一批 Tag、Attribute。可以对照如下所示的基于 XML 的配置示例来对这些定义的配置项进行理解:

<sharding:data-source id="shardingDataSource">
         <sharding:sharding-rule data-source-names="ds0,ds1">
             <sharding:table-rules>
                 <sharding:table-rule …/>
               <sharding:table-rule …/>
               …
             </sharding:table-rules>
             …
         </sharding:sharding-rule>
 </sharding:data-source>

在 sharding-jdbc-spring-namespace 代码工程的 META-INF/namespace 文件夹找到 sharding.xsd 文件,其基本结构:

<xsd:schema xmlns="http:///schema/shardingsphere/sharding"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:beans="http://www.springframework.org/schema/beans"
             xmlns:encrypt="http:///schema/shardingsphere/encrypt"
             targetNamespace="http:///schema/shardingsphere/sharding"
             elementFormDefault="qualified" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http:///schema/shardingsphere/encrypt http:///schema/shardingsphere/encrypt/encrypt.xsd">
     <xsd:import namespace="http://www.springframework.org/schema/beans" schemaLocation="http://www.springframework.org/schema/beans/spring-beans.xsd" />
     <xsd:import namespace="http:///schema/shardingsphere/encrypt" schemaLocation="http:///schema/shardingsphere/encrypt/encrypt.xsd"/>
     <xsd:element name="data-source">
         <xsd:complexType>
             <xsd:all>
                 <xsd:element ref="sharding-rule" />
                 <xsd:element ref="props" minOccurs="0" />
             </xsd:all>
             <xsd:attribute name="id" type="xsd:string" use="required" />
         </xsd:complexType>
   </xsd:element>
   …
 </xsd:schema>

“data-source”这 element包含“sharding-rule”和“props”这两个子 element。

“data-source”还包含一个“id”属性。对“sharding-rule”,可有很多内嵌的属性,sharding.xsd 文件中对这些属性都做了定义。

sharding.xsd 中通过使用 xsd:import 标签还引入两个 namespace:

有了业务对象类、XSD 文件的定义,来看 NamespaceHandler 实现类 ShardingNamespaceHandler:

public final class ShardingNamespaceHandler extends NamespaceHandlerSupport {
   @Overridepublic void init() {        registerBeanDefinitionParser(ShardingDataSourceBeanDefinitionParserTag.ROOT_TAG, new ShardingDataSourceBeanDefinitionParser());  registerBeanDefinitionParser(ShardingStrategyBeanDefinitionParserTag.STANDARD_STRATEGY_ROOT_TAG, new ShardingStrategyBeanDefinitionParser());  …   } }

直接使用 registerBeanDefinitionParser 方法来完成标签项与具体的 BeanDefinitionParser 类之间的对应关系。

看ShardingDataSourceBeanDefinitionParser#parseInternal:

@Override
 protected AbstractBeanDefinition parseInternal(final Element element, final ParserContext parserContext) {
       //构建针对 SpringShardingDataSource 的 BeanDefinitionBuilder
         BeanDefinitionBuilder factory = BeanDefinitionBuilder.rootBeanDefinition(SpringShardingDataSource.class);
        //解析构造函数中的 DataSource 参数
         factory.addConstructorArgValue(parseDataSources(element));
 //解析构造函数中 ShardingRuleConfiguration 参数        factory.addConstructorArgValue(parseShardingRuleConfiguration(element));
        //解析构造函数中 Properties 参数
         factory.addConstructorArgValue(parseProperties(element, parserContext));
         factory.setDestroyMethodName("close");
         return factory.getBeanDefinition();
 }

自定义一个 BeanDefinitionBuilder 并将其绑定到前面定义的业务对象类 SpringShardingDataSource。然后,通过三个 addConstructorArgValue 方法的调用,分别为 SpringShardingDataSource 构造函数中所需的 dataSourceMap、shardingRuleConfiguration 以及 props 参数进行赋值。

parseDataSources方法

private Map<String, RuntimeBeanReference> parseDataSources(final Element element) {
         Element shardingRuleElement = DomUtils.getChildElementByTagName(element, ShardingDataSourceBeanDefinitionParserTag.SHARDING_RULE_CONFIG_TAG);
         List<String> dataSources = Splitter.on(",").trimResults().splitToList(shardingRuleElement.getAttribute(ShardingDataSourceBeanDefinitionParserTag.DATA_SOURCE_NAMES_TAG));
         Map<String, RuntimeBeanReference> result = new ManagedMap<>(dataSources.size());
         for (String each : dataSources) {
             result.put(each, new RuntimeBeanReference(each));
         }
         return result;
 }

获取配置的“ds0,ds1”字符串并拆分,然后基于每个代表具体 DataSource 的名称构建 RuntimeBeanReference 对象并进行返回,这样就可以把在 Spring 容器中定义的其他 Bean 加载到 BeanDefinitionBuilder。

最后,在 META-INF 目录提供spring.schemas 文件:

http\:///schema/shardingsphere/sharding/sharding.xsd=META-INF/namespace/sharding.xsd
 http\:///schema/shardingsphere/masterslave/master-slave.xsd=META-INF/namespace/master-slave.xsd
 http\:///schema/shardingsphere/encrypt/encrypt.xsd=META-INF/namespace/encrypt.xsd

spring.handlers 内容:

http\:///schema/shardingsphere/sharding=org.apache.shardingsphere.shardingjdbc.spring.namespace.handler.ShardingNamespaceHandler
 http\:///schema/shardingsphere/masterslave=org.apache.shardingsphere.shardingjdbc.spring.namespace.handler.MasterSlaveNamespaceHandler
 http\:///schema/shardingsphere/encrypt=org.apache.shardingsphere.shardingjdbc.spring.namespace.handler.EncryptNamespaceHandler

ShardingSphere 中基于命名空间机制与 Spring 进行系统集成的实现过程介绍完。