ShardingSphere如何完成与Spring家族无缝整合的?

打印 上一主题 下一主题

主题 919|帖子 919|积分 2757

体系集成即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 类,即业务对象类:
  1. public class SpringShardingDataSource extends ShardingDataSource {
  2.    
  3.     public SpringShardingDataSource(final Map<String, DataSource> dataSourceMap, final ShardingRuleConfiguration shardingRuleConfiguration, final Properties props) throws SQLException {
  4.         super(dataSourceMap, new ShardingRule(shardingRuleConfiguration, dataSourceMap.keySet()), props);
  5.     }
  6. }
复制代码
只是对 ShardingDataSource 的简单封装,无任何实际操作。
设置项标签的定义类

简单的工具类,定义标签的名称。ShardingSphere的这些类都以“BeanDefinitionParserTag”末端,如ShardingDataSourceBeanDefinitionParserTag:
  1. public final class ShardingDataSourceBeanDefinitionParserTag {
  2.     public static final String ROOT_TAG = "data-source";
  3.     public static final String SHARDING_RULE_CONFIG_TAG = sharding-rule";
  4.     public static final String PROPS_TAG = "props";
  5.         public static final String DATA_SOURCE_NAMES_TAG = "data-source-names";
  6.         public static final String DEFAULT_DATA_SOURCE_NAME_TAG = "default-data-source-name";
  7.     public static final String TABLE_RULES_TAG = "table-rules";
  8.     …
  9. }
复制代码
定义一批 Tag、Attribute。可以对照如下所示的基于 XML 的设置示例来对这些定义的设置项举行理解:
  1. <sharding:data-source id="shardingDataSource">
  2.         <sharding:sharding-rule data-source-names="ds0,ds1">
  3.             <sharding:table-rules>
  4.                 <sharding:table-rule …/>
  5.                     <sharding:table-rule …/>
  6.                     …
  7.             </sharding:table-rules>
  8.             …
  9.         </sharding:sharding-rule>
  10. </sharding:data-source>
复制代码
在 sharding-jdbc-spring-namespace 代码工程的 META-INF/namespace 文件夹找到 sharding.xsd 文件,其基本结构:
  1. <xsd:schema xmlns="http://shardingsphere.apache.org/schema/shardingsphere/sharding"
  2.             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  3.             xmlns:beans="http://www.springframework.org/schema/beans"
  4.             xmlns:encrypt="http://shardingsphere.apache.org/schema/shardingsphere/encrypt"
  5.             targetNamespace="http://shardingsphere.apache.org/schema/shardingsphere/sharding"
  6.             elementFormDefault="qualified" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  7.             xsi:schemaLocation="http://shardingsphere.apache.org/schema/shardingsphere/encrypt http://shardingsphere.apache.org/schema/shardingsphere/encrypt/encrypt.xsd">
  8.     <xsd:import namespace="http://www.springframework.org/schema/beans" schemaLocation="http://www.springframework.org/schema/beans/spring-beans.xsd" />
  9.     <xsd:import namespace="http://shardingsphere.apache.org/schema/shardingsphere/encrypt" schemaLocation="http://shardingsphere.apache.org/schema/shardingsphere/encrypt/encrypt.xsd"/>
  10.     <xsd:element name="data-source">
  11.         <xsd:complexType>
  12.             <xsd:all>
  13.                 <xsd:element ref="sharding-rule" />
  14.                 <xsd:element ref="props" minOccurs="0" />
  15.             </xsd:all>
  16.             <xsd:attribute name="id" type="xsd:string" use="required" />
  17.         </xsd:complexType>
  18.         </xsd:element>
  19.         …
  20. </xsd:schema>
复制代码
“data-source”这 element包罗“sharding-rule”和“props”这两个子 element。
“data-source”还包罗一个“id”属性。对“sharding-rule”,可有很多内嵌的属性,sharding.xsd 文件中对这些属性都做了定义。
sharding.xsd 中通过利用 xsd:import 标签还引入两个 namespace:
有了业务对象类、XSD 文件的定义,来看 NamespaceHandler 实现类 ShardingNamespaceHandler:
  1. public final class ShardingNamespaceHandler extends NamespaceHandlerSupport {
  2.   @Overridepublic void init() {        registerBeanDefinitionParser(ShardingDataSourceBeanDefinitionParserTag.ROOT_TAG, new ShardingDataSourceBeanDefinitionParser());  registerBeanDefinitionParser(ShardingStrategyBeanDefinitionParserTag.STANDARD_STRATEGY_ROOT_TAG, new ShardingStrategyBeanDefinitionParser());  …   } }
复制代码
直接利用 registerBeanDefinitionParser 方法来完成标签项与具体的 BeanDefinitionParser 类之间的对应关系。
看ShardingDataSourceBeanDefinitionParser#parseInternal:
  1. @Override
  2. protected AbstractBeanDefinition parseInternal(final Element element, final ParserContext parserContext) {
  3.             //构建针对 SpringShardingDataSource 的 BeanDefinitionBuilder
  4.         BeanDefinitionBuilder factory = BeanDefinitionBuilder.rootBeanDefinition(SpringShardingDataSource.class);
  5.        //解析构造函数中的 DataSource 参数
  6.         factory.addConstructorArgValue(parseDataSources(element));
  7. //解析构造函数中 ShardingRuleConfiguration 参数        factory.addConstructorArgValue(parseShardingRuleConfiguration(element));
  8.        //解析构造函数中 Properties 参数
  9.         factory.addConstructorArgValue(parseProperties(element, parserContext));
  10.         factory.setDestroyMethodName("close");
  11.         return factory.getBeanDefinition();
  12. }
复制代码
自定义一个 BeanDefinitionBuilder 并将其绑定到前面定义的业务对象类 SpringShardingDataSource。然后,通过三个 addConstructorArgValue 方法的调用,分别为 SpringShardingDataSource 构造函数中所需的 dataSourceMap、shardingRuleConfiguration 以及 props 参数举行赋值。
parseDataSources方法
  1. private Map<String, RuntimeBeanReference> parseDataSources(final Element element) {
  2.         Element shardingRuleElement = DomUtils.getChildElementByTagName(element, ShardingDataSourceBeanDefinitionParserTag.SHARDING_RULE_CONFIG_TAG);
  3.         List<String> dataSources = Splitter.on(",").trimResults().splitToList(shardingRuleElement.getAttribute(ShardingDataSourceBeanDefinitionParserTag.DATA_SOURCE_NAMES_TAG));
  4.         Map<String, RuntimeBeanReference> result = new ManagedMap<>(dataSources.size());
  5.         for (String each : dataSources) {
  6.             result.put(each, new RuntimeBeanReference(each));
  7.         }
  8.         return result;
  9. }
复制代码
获取设置的“ds0,ds1”字符串并拆分,然后基于每个代表具体 DataSource 的名称构建 RuntimeBeanReference 对象并举行返回,这样就可以把在 Spring 容器中定义的其他 Bean 加载到 BeanDefinitionBuilder。
最后,在 META-INF 目次提供spring.schemas 文件:
  1. http\://shardingsphere.apache.org/schema/shardingsphere/sharding/sharding.xsd=META-INF/namespace/sharding.xsd
  2. http\://shardingsphere.apache.org/schema/shardingsphere/masterslave/master-slave.xsd=META-INF/namespace/master-slave.xsd
  3. http\://shardingsphere.apache.org/schema/shardingsphere/encrypt/encrypt.xsd=META-INF/namespace/encrypt.xsd
复制代码
spring.handlers 内容:
  1. http\://shardingsphere.apache.org/schema/shardingsphere/sharding=org.apache.shardingsphere.shardingjdbc.spring.namespace.handler.ShardingNamespaceHandler
  2. http\://shardingsphere.apache.org/schema/shardingsphere/masterslave=org.apache.shardingsphere.shardingjdbc.spring.namespace.handler.MasterSlaveNamespaceHandler
  3. http\://shardingsphere.apache.org/schema/shardingsphere/encrypt=org.apache.shardingsphere.shardingjdbc.spring.namespace.handler.EncryptNamespaceHandler
复制代码
ShardingSphere 中基于命名空间机制与 Spring 举行体系集成的实现过程介绍完。
3 自定义 starter 集成 Spring Boot

与基于命名空间实现方式一样,ShardingSphere 提供:

  • sharding-jdbc-spring-boot-starter
  • sharding-jdbc-orchestration-spring-boot-starter
Spring Boot 工程先关注 META-INF 文件夹下的 spring.factories 文件。Spring Boot 提供
3.1 SpringFactoriesLoader 类

运行机制雷同SPI 机制,只不过以服务接口命名的文件放在 META-INF/spring.factories,对应 Key 为 EnableAutoConfiguration。
SpringFactoriesLoader 查找所有 META-INF/spring.factories 下的设置文件,把 Key=EnableAutoConfiguration 对应设置项通过反射,实例化为设置类并加载到容器。如sharding-jdbc-spring-boot-starter 中的文件内容:
  1. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  2. org.apache.shardingsphere.shardingjdbc.spring.boot.SpringBootConfiguration
复制代码
SpringBootConfiguration类就会在 Spring Boot 启动过程中都能够通过 SpringFactoriesLoader 被加载到运行时环境。
① SpringBootConfiguration 中的注解
  1. @Configuration
  2. @ComponentScan("org.apache.shardingsphere.spring.boot.converter")
  3. @EnableConfigurationProperties({
  4.         SpringBootShardingRuleConfigurationProperties.class,
  5.         SpringBootMasterSlaveRuleConfigurationProperties.class, SpringBootEncryptRuleConfigurationProperties.class, SpringBootPropertiesConfigurationProperties.class})
  6. @ConditionalOnProperty(prefix = "spring.shardingsphere", name = "enabled", havingValue = "true", matchIfMissing = true)
  7. @AutoConfigureBefore(DataSourceAutoConfiguration.class)
  8. @RequiredArgsConstructor
  9. public class SpringBootConfiguration implements EnvironmentAware
复制代码
@Configuration 注解属于 Spring 容器管理的内容,表明该类是一个设置类,可启动组件扫描,将带 @Bean 注解的实体实例化为 bean。
Spring 容器管理的@ComponentScan 注解:扫描基于 @Component 等注解所标注的类所在包下的所有必要注入的类,并把相干 Bean 定义批量加载到IoC容器。
Spring Boot 应用程序中同样必要这个功能。这里必要举行扫描的包路径位于另一代码工程 sharding-spring-boot-util 的 org.apache.shardingsphere.spring.boot.converter 包。
然后,看到 @EnableConfigurationProperties 注解:使添加 @ConfigurationProperties 注解的类生效。Spring Boot 中,若一个类只用 @ConfigurationProperties 注解,然后该类没有在扫描路径下或没利用 @Component 等注解,就会导致无法被扫描为 bean,就须在设置类利用 @EnableConfigurationProperties 注解去指定这个类,才能使 @ConfigurationProperties 生效,并作为一个 bean 添加进 spring 容器中。
这里的 @EnableConfigurationProperties 注解包罗四个具体的 ConfigurationProperties。
如SpringBootShardingRuleConfigurationProperties定义,直接继承 sharding-core-common 的 YamlShardingRuleConfiguration:
  1. @ConfigurationProperties(prefix = "spring.shardingsphere.sharding")
  2. public class SpringBootShardingRuleConfigurationProperties extends YamlShardingRuleConfiguration {
  3. }
复制代码
SpringBootConfiguration 上的下一注解是 @ConditionalOnProperty,只有当所提供的属性属于 true 时才实例化 Bean。
@AutoConfigureBefore用在类名上,标识在加载当前类之前必要加载注解中所设置的设置类。明确在加载 SpringBootConfiguration 类之前,Spring Boot 会先加载 DataSourceAutoConfiguration。这作用与创建各种 DataSource 相干。
② SpringBootConfiguration 中的功能

ShardingSphere对外入口就是各种 DataSource,因此SpringBootConfiguration中提供一批创建不同 DataSource 的入口方法,如shardingDataSource:
  1. @Bean
  2. @Conditional(ShardingRuleCondition.class)
  3. public DataSource shardingDataSource() throws SQLException {
  4.         return ShardingDataSourceFactory.createDataSource(dataSourceMap, new ShardingRuleConfigurationYamlSwapper().swap(shardingRule), props.getProps());
  5. }
复制代码
该方法上添加两个注解:

  • @Bean
  • @Conditional 注解,只有满足指定条件的情况下才加载这 Bean。@Conditional 注解设置了一个 ShardingRuleCondition:
  1. public final class ShardingRuleCondition extends SpringBootCondition {
  2.    
  3.     @Override
  4.     public ConditionOutcome getMatchOutcome(final ConditionContext conditionContext, final AnnotatedTypeMetadata annotatedTypeMetadata) {
  5.         boolean isMasterSlaveRule = new MasterSlaveRuleCondition().getMatchOutcome(conditionContext, annotatedTypeMetadata).isMatch();
  6.         boolean isEncryptRule = new EncryptRuleCondition().getMatchOutcome(conditionContext, annotatedTypeMetadata).isMatch();
  7.         return isMasterSlaveRule || isEncryptRule ? ConditionOutcome.noMatch("Have found master-slave or encrypt rule in environment") : ConditionOutcome.match();
  8.     }
  9. }
复制代码
ShardingRuleCondition 是一个标准的 SpringBootCondition,实现 getMatchOutcome 抽象方法。SpringBootCondition 的作用就是代表一种用于注册类或加载 Bean 的条件。ShardingRuleCondition 类的实现上分别调用了 MasterSlaveRuleCondition 和 EncryptRuleCondition 来判断是否满足这两个 SpringBootCondition。对ShardingRuleCondition,只有在两个条件都不满足的情况下才被加载。
SpringBootConfiguration 实现 Spring 的 EnvironmentAware 接口。在 Spring Boot 中,当一个类实现了 EnvironmentAware 接口并重写setEnvironment,在代码工程启动时就可得到 application.properties 设置文件中各个设置项的属性值。SpringBootConfiguration#setEnvironment :
  1. @Override
  2. public final void setEnvironment(final Environment environment) {
  3.         String prefix = "spring.shardingsphere.datasource.";
  4.         for (String each : getDataSourceNames(environment, prefix)) {
  5.             try {
  6.                 dataSourceMap.put(each, getDataSource(environment, prefix, each));
  7.             } catch (final ReflectiveOperationException ex) {
  8.                 throw new ShardingException("Can't find datasource type!", ex);
  9.             } catch (final NamingException namingEx) {
  10.                 throw new ShardingException("Can't find JNDI datasource!", namingEx);
  11.             }
  12.         }
  13. }
复制代码
获取“spring.shardingsphere.datasource.name”或“spring.shardingsphere.datasource.names”设置项,然后根据该设置项中所指定的 DataSource 信息构建新的 DataSource 并加载到 dataSourceMap 这个 LinkedHashMap。
  1. spring.shardingsphere.datasource.names=ds0,ds1
  2. spring.shardingsphere.datasource.ds0.type=com.alibaba.druid.pool.DruidDataSource
  3. spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver
  4. spring.shardingsphere.datasource.ds0.url=jdbc:mysql://localhost/ds0
  5. spring.shardingsphere.datasource.ds0.username=root
  6. spring.shardingsphere.datasource.ds0.password=root
  7. spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
  8. spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
  9. spring.shardingsphere.datasource.ds1.url=jdbc:mysql://localhost/ds1
  10. spring.shardingsphere.datasource.ds1.username=root
  11. spring.shardingsphere.datasource.ds1.password=root
复制代码
至此,整个 SpringBootConfiguration 的实现过程介绍完毕。
3.2 源码剖析到开发

如必要实现一个自定义的框架或工具类,从面向开发人员的角度讲,最好能与 Spring 等主流的开发框架举行集成,以便提供最低的学习和维护成本。与 Spring 框架的集成过程都有固定的开发步骤,就可模仿 ShardingSphere 中的做法自己实现这些步骤。
FAQ

Q:ShardingSphere 集成 Spring Boot 时,SpringBootConfiguration 类上的注解有哪些,分别起啥作用?
在集成 ShardingSphere 和 Spring Boot 时,通常在 SpringBootConfiguration 类上利用以下几个注解:

  • @SpringBootApplication

    • 作用:这是一个组合注解,包罗了 @Configuration, @EnableAutoConfiguration, 和 @ComponentScan 三个注解的功能。
    • 详细解释:

      • @Configuration:表明这个类是一个 Spring 设置类,可以定义 Spring beans。
      • @EnableAutoConfiguration:启用 Spring Boot 的自动设置机制,尝试根据类路径下的 jar 包和已定义的 beans 自动设置 Spring 应用程序。
      • @ComponentScan:告诉 Spring 扫描 @Component (包罗 @Service, @Repository, @Controller 等) 注解所在的包,以便发现和注册这些 beans。


  • @EnableTransactionManagement

    • 作用:启用 Spring 的注解驱动的事务管理功能,允许在方法上利用 @Transactional 注解举行事务管理。

  • @ShardingSphereDataSource

    • 作用:这是一个 ShardingSphere 提供的注解,用于创建和设置 ShardingSphere 的数据源,支持分库分表和读写分离等功能。
    • 详细解释:该注解的具体作用包罗设置 ShardingSphere 的数据源计谋、分片计谋、读写分离计谋等。

一个典型的 SpringBootConfiguration 类可能会如下所示:
  1. import org.apache.shardingsphere.driver.api.yaml.YamlShardingSphereDataSourceFactory;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.context.annotation.Bean;
  5. import org.springframework.transaction.annotation.EnableTransactionManagement;
  6. import javax.sql.DataSource;
  7. import java.io.File;
  8. @SpringBootApplication
  9. @EnableTransactionManagement
  10. public class SpringBootConfiguration {
  11.     public static void main(String[] args) {
  12.         SpringApplication.run(SpringBootConfiguration.class, args);
  13.     }
  14.     @Bean
  15.     public DataSource dataSource() throws Exception {
  16.         // 假设有一个 sharding 配置文件 sharding-databases-tables.yaml
  17.         return YamlShardingSphereDataSourceFactory.createDataSource(new File("path/to/sharding-databases-tables.yaml"));
  18.     }
  19. }
复制代码
详解各个注解的作用


  • @SpringBootApplication

    • @Configuration:将类标识为设置类,可以用来定义 Spring beans。
    • @EnableAutoConfiguration:启用 Spring Boot 自动设置,这样 Spring Boot 会根据类路径下的 jar 包和已定义的 beans 自动设置 Spring 应用。
    • @ComponentScan:告诉 Spring 在指定包下扫描 @Component 注解的类并注册这些类为 Spring beans。

  • @EnableTransactionManagement

    • 允许利用 @Transactional 注解来管理事务,使得可以通过注解的方式声明事务的范围。

  • @ShardingSphereDataSource

    • 设置 ShardingSphere 数据源,使得可以利用 ShardingSphere 提供的分库分表和读写分离功能。这个注解必要团结具体的 ShardingSphere 设置来利用,如上面的 YamlShardingSphereDataSourceFactory.createDataSource 方法。

通过这些注解,可以快速且简便地设置和利用 ShardingSphere 与 Spring Boot 集成,利用 Spring Boot 的自动设置和管理功能,加上 ShardingSphere 的分库分表和读写分离功能,构建一个高效且可扩展的分布式数据库体系。
关注我,紧跟本系列专栏文章,咱们下篇再续!
作者简介:魔都技术专家,多家大厂后端一线研发经验,在分布式体系、和大数据体系等方面有多年的研究和实践经验,拥有从零到一的大数据平台和基础架构研发经验,对分布式存储、数据平台架构、数据仓库等领域都有丰富实践经验。
各大技术社区头部专家博主。具有丰富的引领团队经验,深厚业务架构和解决方案的积累。
负责:

  • 中央/分销预订体系性能优化
  • 活动&优惠券等营销中台建设
  • 交易平台及数据中台等架构和开发设计
  • 车联网核心平台-物联网毗连平台、大数据平台架构设计及优化
目前主攻低落软件复杂性设计、构建高可用体系方向。
参考:
本文由博客一文多发平台 OpenWrite 发布!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

去皮卡多

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表