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

发布时间:2025-05-17 10:58:36 作者:益华网络 来源:undefined 浏览量(1) 点赞(1)
摘要:来源:JavaEdge 系统集成,即ShardingSphere 和 Spring 框架的集成。 ShardingSphere实现两种系统集成机制:命名空间(namespace),扩展 Spring Schema 来实现与 Spring 框架集成编写自定义 starter 组件完成与 Spring Boot 集成1 基于命

来源:JavaEdge

系统集成,即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 配置文件

1.2 ShardingSphere 集成 Spring

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

sharding-jdbc-spring-namespace

sharding-jdbc-orchestration-spring-namespace

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

sharding-jdbc-spring-namespace又包含:

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

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

1.3 SpringShardingDataSource

专门用于与 Spring 进行集成的业务对象类:

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 的简单封装,无任何实际操作。

1.4 配置项标签的定义类

定义标签的名称。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://shardingsphere.apache.org/schema/shardingsphere/sharding"            xmlns:xsd="http://www.w3.org/2001/XMLSchema"            xmlns:beans="http://www.springframework.org/schema/beans"            xmlns:encrypt="http://shardingsphere.apache.org/schema/shardingsphere/encrypt"            targetNamespace="http://shardingsphere.apache.org/schema/shardingsphere/sharding"            elementFormDefault="qualified" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"            xsi:schemaLocation="http://shardingsphere.apache.org/schema/shardingsphere/encrypt http://shardingsphere.apache.org/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://shardingsphere.apache.org/schema/shardingsphere/encrypt" schemaLocation="http://shardingsphere.apache.org/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:

Spring 中的http://www.springframework.org/schema/beansShardingSphere 自身的http://shardingsphere.apache.org/schema/shardingsphere/encrypt,该命名空间的定义位于与 sharding.xsd 同目录下的 encrypt.xsd文件中

有了业务对象类、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:

@Overrideprotected 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\://shardingsphere.apache.org/schema/shardingsphere/sharding/sharding.xsd=META-INF/namespace/sharding.xsd

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

http\://shardingsphere.apache.org/schema/shardingsphere/encrypt/encrypt.xsd=META-INF/namespace/encrypt.xsd

spring.handlers 内容:

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

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

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

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

2 自定义 starter 集成 Spring Boot

ShardingSphere提供:

sharding-jdbc-spring-boot-startersharding-jdbc-orchestration-spring-boot-starter

Spring Boot先关注 META-INF 的 spring.factories 文件。Spring Boot 提供

2.1 SpringFactoriesLoader 类

类似SPI 机制,只不过以服务接口命名的文件放在 META-INF/spring.factories,对应 Key 为 EnableAutoConfiguration。

SpringFactoriesLoader 查找所有 META-INF/spring.factories 下的配置文件,把 Key=EnableAutoConfiguration 对应配置项通过反射,实例化为配置类并加载到容器。如sharding-jdbc-spring-boot-starter 中的文件内容:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

org.apache.shardingsphere.shardingjdbc.spring.boot.SpringBootConfiguration

SpringBootConfiguration类就会在 Spring Boot 启动过程中都能够通过 SpringFactoriesLoader 被加载到运行时环境。

2.2 SpringBootConfiguration的注解

@Configuration:表明该类是一个配置类,可启动组件扫描,将@Bean 注解的实例化为 bean@ComponentScan:扫描基于 @Component 等注解所标注的类所在包下的所有需要注入的类,并把相关 Bean 定义批量加载到IoC容器

需扫描的包路径位于另一工程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:

@ConfigurationProperties(prefix = "spring.shardingsphere.sharding"

)

public class SpringBootShardingRuleConfigurationProperties extends YamlShardingRuleConfiguration 

{

}

@ConditionalOnProperty,只有当所提供的属性属于 true 时才实例化 Bean。

@AutoConfigureBefore用在类名上,标识在加载当前类之前需要加载注解中所设置的配置类。明确在加载 SpringBootConfiguration 类之前,Spring Boot 会先加载 DataSourceAutoConfiguration。这作用与创建各种 DataSource 相关。

2.3 SpringBootConfiguration 中的功能

ShardingSphere对外入口就是各种 DataSource,因此SpringBootConfiguration中提供一批创建不同 DataSource 的入口方法,如shardingDataSource:

@Bean@Conditional(ShardingRuleCondition.class

)

public DataSource shardingDataSource() throws SQLException 

{

        return ShardingDataSourceFactory.createDataSource(dataSourceMap, new

 ShardingRuleConfigurationYamlSwapper().swap(shardingRule), props.getProps());

}

该方法上添加两个注解:

@Bean@Conditional 注解,只有满足指定条件的情况下才加载这 Bean。@Conditional 注解设置了一个 ShardingRuleCondition:public final class ShardingRuleCondition extends SpringBootCondition 

{

    @Override    public ConditionOutcome getMatchOutcome(final ConditionContext conditionContext, final AnnotatedTypeMetadata annotatedTypeMetadata) 

{

        boolean isMasterSlaveRule = new

 MasterSlaveRuleCondition().getMatchOutcome(conditionContext, annotatedTypeMetadata).isMatch();

        boolean isEncryptRule = new

 EncryptRuleCondition().getMatchOutcome(conditionContext, annotatedTypeMetadata).isMatch();

        return isMasterSlaveRule || isEncryptRule ? ConditionOutcome.noMatch("Have found master-slave or encrypt rule in environment"

) : ConditionOutcome.match();

    }

}

标准的 SpringBootCondition,实现 getMatchOutcome 抽象方法。代表一种用于注册类或加载 Bean 的条件。ShardingRuleCondition 类的实现上分别调用MasterSlaveRuleCondition、EncryptRuleCondition 判断是否满足这两个 SpringBootCondition。对ShardingRuleCondition,只有在两个条件都不满足的情况下才被加载。

SpringBootConfiguration 实现 Spring 的 EnvironmentAware 接口。Spring Boot中,当一个类实现了 EnvironmentAware 接口并重写setEnvironment,在代码工程启动时就可获得 application.properties 配置文件中各个配置项的属性值。SpringBootConfiguration#setEnvironment :

@Overridepublic final void setEnvironment(final Environment environment) 

{

        String prefix = "spring.shardingsphere.datasource."

;

        for

 (String each : getDataSourceNames(environment, prefix)) {

            try

 {

                dataSourceMap.put(each, getDataSource(environment, prefix, each));

            } catch (final

 ReflectiveOperationException ex) {

                throw new ShardingException("Cant find datasource type!"

, ex);

            } catch (final

 NamingException namingEx) {

                throw new ShardingException("Cant find JNDI datasource!"

, namingEx);

            }

        }

}

获取“spring.shardingsphere.datasource.name”或“spring.shardingsphere.datasource.names”配置项,然后根据该配置项中所指定的 DataSource 信息构建新的 DataSource 并加载到 dataSourceMap 这个 LinkedHashMap。

spring.shardingsphere.datasource.names=ds0,ds1

spring.shardingsphere.datasource.ds0.type=com.alibaba.druid.pool.DruidDataSource

spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver

spring.shardingsphere.datasource.ds0.url=jdbc:mysql://localhost/ds0

spring.shardingsphere.datasource.ds0.username=root

spring.shardingsphere.datasource.ds0.password=root

spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource

spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver

spring.shardingsphere.datasource.ds1.url=jdbc:mysql://localhost/ds1

spring.shardingsphere.datasource.ds1.username=root

spring.shardingsphere.datasource.ds1.password=root

3 总结

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

FAQ

Q:ShardingSphere 集成 Spring Boot 时,SpringBootConfiguration 类上的注解有哪些,分别起啥作用?

在集成 ShardingSphere 和 Spring Boot 时,通常在 SpringBootConfiguration 类上使用以下几个注解:

@SpringBootApplication

@Configuration:表明这个类是一个 Spring 配置类,可以定义 Spring beans。@EnableAutoConfiguration:启用 Spring Boot 的自动配置机制,尝试根据类路径下的 jar 包和已定义的 beans 自动配置 Spring 应用程序。@ComponentScan:告诉 Spring 扫描 @Component (包括 @Service, @Repository, @Controller 等) 注解所在的包,以便发现和注册这些 beans。作用:这是一个组合注解,包含了 @Configuration, @EnableAutoConfiguration, 和 @ComponentScan 三个注解的功能。详细解释:

@EnableTransactionManagement

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

@ShardingSphereDataSource

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

典型的 SpringBootConfiguration 类:

import

 org.apache.shardingsphere.driver.api.yaml.YamlShardingSphereDataSourceFactory;

import

 org.springframework.boot.SpringApplication;

import

 org.springframework.boot.autoconfigure.SpringBootApplication;

import

 org.springframework.context.annotation.Bean;

import

 org.springframework.transaction.annotation.EnableTransactionManagement;

import

 javax.sql.DataSource;

import

 java.io.File;

@SpringBootApplication@EnableTransactionManagementpublic class SpringBootConfiguration 

{

    public static void main(String[] args) 

{

        SpringApplication.run(SpringBootConfiguration.classargs)

;

    }

    @Bean    public DataSource dataSource() throws Exception 

{

        // 假设有一个 sharding 配置文件 sharding-databases-tables.yaml        return YamlShardingSphereDataSourceFactory.createDataSource(new File("path/to/sharding-databases-tables.yaml"

));

    }

}

详解各个注解的作用

@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 的分库分表和读写分离功能,构建一个高效且可扩展的分布式数据库系统。

二维码

扫一扫,关注我们

声明:本文由【益华网络】编辑上传发布,转载此文章须经作者同意,并请附上出处【益华网络】及本页链接。如内容、图片有任何版权问题,请联系我们进行处理。

感兴趣吗?

欢迎联系我们,我们愿意为您解答任何有关网站疑难问题!

您身边的【网站建设专家】

搜索千万次不如咨询1次

主营项目:网站建设,手机网站,响应式网站,SEO优化,小程序开发,公众号系统,软件开发等

立即咨询 15368564009
在线客服
嘿,我来帮您!