【Java】SPI在Shardingsphere中的使用总结

本文详细介绍了Apache ShardingSphere如何利用SPI(Service Provider Interface)来增强其可扩展性,特别是在主键生成策略方面。以ShardingKeyGenerator接口为例,文章探讨了四种默认实现:自增、自减、UUID和SnowFlake。通过SPI的初始化过程,如NewInstanceServiceLoader的注册和加载机制,展示了如何配置和使用IncrementKeyGenerator作为默认实现。文中还提及了配置文件(如rdb/shardingNamespace.xml)在指定主键生成规则中的作用,并提供了获取和过滤具体实现类的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

  Shardingsphere大量使用了SPI技术,提供良好的可扩展性

  参考:https://shardingsphere.apache.org/document/legacy/4.x/document/en/features/spi/

  SPI基本概念:https://www.cnblogs.com/jy107600/p/11464985.html

 

本文以ShardingKeyGenerator接口为例说明SPI在Shardingsphere中的使用

  本文的代码都可以在项目源码中找到:https://github.com/apache/shardingsphere/tree/4.1.1

 

1. ShardingKeyGenerator接口及其子类

org.apache.shardingsphere.spi.keygen.ShardingKeyGenerator
{
    Comparable<?> generateKey();
}    

ShardingKeyGenerator默认实现了四种生成主键的方式,分别是自增、自减、UUID、SnowFlake方式

org.apache.shardingsphere.shardingjdbc.orchestration.spring.fixture.IncrementKeyGenerator
org.apache.shardingsphere.shardingjdbc.orchestration.spring.fixture.DecrementKeyGenerator
org.apache.shardingsphere.core.strategy.keygen.UUIDShardingKeyGenerator
org.apache.shardingsphere.core.strategy.keygen.SnowflakeShardingKeyGenerator

2. ShardingKeyGenerator SPI的初始化

package org.apache.shardingsphere.spi.algorithm.keygen;

public final class ShardingKeyGeneratorServiceLoader extends TypeBasedSPIServiceLoader<ShardingKeyGenerator> {
    
    // 静态代码块注册ShardingKeyGenerator所有实现类
    static {
        NewInstanceServiceLoader.register(ShardingKeyGenerator.class);
    }
    
    public ShardingKeyGeneratorServiceLoader() {
        super(ShardingKeyGenerator.class);
    }
}

NewInstanceServiceLoader.register方法实现

  • NewInstanceServiceLoader 初始化接口和子类关系的集合,缓存了所有SPI接口和子类的关系
  • 集合类型为:Map<Class, Collection<Class<?>>> SERVICE_MAP
package org.apache.shardingsphere.spi;

public final class NewInstanceServiceLoader {
    
    private static final Map<Class, Collection<Class<?>>> SERVICE_MAP = new HashMap<>();
    
    public static <T> void register(final Class<T> service) {
        // 循环时注册子类及建立接口和子类关系,放在map中
        for (T each : ServiceLoader.load(service)) {
            registerServiceClass(service, each);
        }
    }
    
    @SuppressWarnings("unchecked")
    private static <T> void registerServiceClass(final Class<T> service, final T instance) {
        Collection<Class<?>> serviceClasses = SERVICE_MAP.get(service);
        if (null == serviceClasses) {
            serviceClasses = new LinkedHashSet<>();
        }
        serviceClasses.add(instance.getClass());
        SERVICE_MAP.put(service, serviceClasses);
    }
    
    @SneakyThrows
    @SuppressWarnings("unchecked")
    public static <T> Collection<T> newServiceInstances(final Class<T> service) {
        Collection<T> result = new LinkedList<>();
        if (null == SERVICE_MAP.get(service)) {
            return result;
        }
        for (Class<?> each : SERVICE_MAP.get(service)) {
            result.add((T) each.newInstance());
        }
        return result;
    }
}

3. 使用IncrementKeyGenerator作为ShardingKeyGenerator的默认实现

package org.apache.shardingsphere.shardingjdbc.spring;
public class GenerateKeyJUnitTest extends AbstractSpringJUnitTest {

@Test
public void assertGenerateKeyColumn() {

    // ShardingRuntimeContext 默认实现:org.apache.shardingsphere.shardingjdbc.spring.datasource.SpringShardingDataSource
     ShardingRuntimeContext runtimeContext = shardingDataSource.getRuntimeContext();
     ShardingRule shardingRule = runtimeContext.getRule();
  
    // ShardingKeyGenerator默认实现:org.apache.shardingsphere.shardingjdbc.spring.fixture.IncrementKeyGenerator
    ShardingKeyGenerator defaultKeyGenerator = shardingRule.getDefaultShardingKeyGenerator();
                                              }
}

上述代码中:ShardingKeyGenerator初始化为IncrementKeyGenerator类的原因

  配置信息:classpath:META-INF/rdb/shardingNamespace.xml

// 这里指定了初始化的默认实现
<sharding:key-generator id="defaultKeyGenerator" type="INCREMENT" column="id" />

<sharding:data-source id="shardingDataSource">
    <sharding:sharding-rule data-source-names="dbtbl_0,dbtbl_1" default-data-source-name="dbtbl_0" default-key-generator-ref="defaultKeyGenerator">
       
    </sharding:sharding-rule>
</sharding:data-source>
  • 通过配置(default-key-generator-ref="defaultKeyGenerator")指定了shardingDataSource数据源默认的主键生成规则
  • <sharding:key-generator id="defaultKeyGenerator" type="INCREMENT" column="id" />
  • type="INCREMENT" 对应的是IncrementShardingKeyGenerator类的type属性值
package org.apache.shardingsphere.shardingjdbc.orchestration.api.yaml.fixture;

public final class IncrementShardingKeyGenerator implements ShardingKeyGenerator {
    
    private static final AtomicInteger SEQUENCE = new AtomicInteger(100);
    
    @Getter
    private final String type = "INCREMENT";
    
    @Getter
    @Setter
    private Properties properties = new Properties();
    
    @Override
    public Comparable<?> generateKey() {
        return SEQUENCE.incrementAndGet();
    }
}
  • 使用其它的主键生成规则
<sharding:key-generator id="defaultKeyGenerator" type="SNOWFLAKE" column="id" />

ShardingRule的初始化(ShardingRule包含了ShardingKeyGenerator的默认实现)

package org.apache.shardingsphere.shardingjdbc.spring.datasource;

public final 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);
    }
}

  初始化defaultShardingKeyGenerator 的代码

package org.apache.shardingsphere.core.rule;

public class ShardingRule implements BaseRule {

public ShardingRule(final ShardingRuleConfiguration shardingRuleConfig, final Collection<String> dataSourceNames) {
    
    // 初始化defaultShardingKeyGenerator
    defaultShardingKeyGenerator = createDefaultKeyGenerator(shardingRuleConfig.getDefaultKeyGeneratorConfig());
}

private ShardingKeyGenerator createDefaultKeyGenerator(final KeyGeneratorConfiguration keyGeneratorConfiguration) {
    ShardingKeyGeneratorServiceLoader serviceLoader = new ShardingKeyGeneratorServiceLoader();
    return containsKeyGeneratorConfiguration(keyGeneratorConfiguration)
            ? serviceLoader.newService(keyGeneratorConfiguration.getType(), keyGeneratorConfiguration.getProperties()) : serviceLoader.newService();
    }
}

       获取指定的主键实现类(loadTypeBasedServices方法)

    1. NewInstanceServiceLoader.newServiceInstances(classType):获取ShardingKeyGenerator接口的所有已实现类缓存集合

    2. Collections2.filter(NewInstanceServiceLoader.newServiceInstances(classType), input -> type.equalsIgnoreCase(input.getType())):根据参数type从缓存集合获取具体的实现,这里是IncrementShardingKeyGenerator

package org.apache.shardingsphere.spi;


@RequiredArgsConstructor
public abstract class TypeBasedSPIServiceLoader<T extends TypeBasedSPI> {
    
    private final Class<T> classType;
    
    public final T newService(final String type, final Properties props) {
        Collection<T> typeBasedServices = loadTypeBasedServices(type);
        if (typeBasedServices.isEmpty()) {
            throw new RuntimeException(String.format("Invalid `%s` SPI type `%s`.", classType.getName(), type));
        }
        T result = typeBasedServices.iterator().next();
        result.setProperties(props);
        return result;
    }
    
    public final T newService() {
        T result = loadFirstTypeBasedService();
        result.setProperties(new Properties());
        return result;
    }
    
    private Collection<T> loadTypeBasedServices(final String type) {
        
        return Collections2.filter(NewInstanceServiceLoader.newServiceInstances(classType), input -> type.equalsIgnoreCase(input.getType()));
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值