SPI机制在ShardingSphere中的应用

举报
周杰伦本人 发表于 2022/10/30 18:35:40 2022/10/30
【摘要】 SPI机制在ShardingSphere中的应用 Sql解析器 获取实例 注册实例 配置中心 注册实例 获取实例 总结 SPI机制在ShardingSphere中的应用之前我们讲过一篇SPI机制在Skywalking中的应用,这篇我们说一说ShardingSphere又是如何使用SPI机制的 Sql解析器Sql解析器的功能就是用来解析SQL的,它的实例创建是通过对应的工厂类SQLParse...

SPI机制在ShardingSphere中的应用

之前我们讲过一篇SPI机制在Skywalking中的应用,这篇我们说一说ShardingSphere又是如何使用SPI机制的

Sql解析器

Sql解析器的功能就是用来解析SQL的,它的实例创建是通过对应的工厂类SQLParserFactory来产生的的,这是一个很重要的一个类。

获取实例

我们看一下SQLParserFactory这个工厂类的获取实例的方法:

public static SQLParser newInstance(final String databaseTypeName, final String sql) {
    for (SQLParserEntry each : NewInstanceServiceLoader.newServiceInstances(SQLParserEntry.class)) {
        if (each.getDatabaseTypeName().equals(databaseTypeName)) {
            return createSQLParser(sql, each);
        }
    }
    throw new UnsupportedOperationException(String.format("Cannot support database type '%s'", databaseTypeName));
}

这里用到了NewInstanceServiceLoader来获取SQLParserEntry的对象信息,这和Java的SPI机制,我们深入看一下这个类的newServiceInstances()方法:

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;
}

这个是直接从缓存中来获取的,那么缓存的数据又从哪里来的呢?我们接着往下看

注册实例

我们从NewInstanceServiceLoader的register()方法可以看出:

public static <T> void register(final Class<T> service) {
        for (T each : ServiceLoader.load(service)) {
            registerServiceClass(service, each);
        }
}
private static <T> void registerServiceClass(final Class<T> service, final T instance) {
  ....
  SERVICE_MAP.put(service, serviceClasses);
}

从这段代码中我们就可以看出来,底层还是使用的Java的SPI机制来加载SQLParserEntry接口的实现类的实例,将 SPI 服务注册到新实例的映射中。因为SQLParserEntry接口所在的包是 org.apache.shardingsphere.sql.parser.spi.SQLParserEntry,所以它的实现类的配置所在的配置文件与这个类权限定名一致。不同的数据库对应的不同的解析SQL的SQLParserEntry实现类不同,mysql中的实现类是MySQLParserEntry,我们在shardingsphere-sql-parser-mysql模块的resoures文件夹的META-INF/services 目录下面可以看到存在org.apache.shardingsphere.sql.parser.spi.SQLParserEntry文件定义了SQLParserEntry的实现类为org.apache.shardingsphere.sql.parser.MySQLParserEntry,而shardingsphere-sql-parser-oracle模块中定义的是org.apache.shardingsphere.sql.parser.OracleParserEntry

配置中心

ShardingSphere的配置中心支持Apollo和Zookeeper,配置中心的灵活切换也使用到了Java的SPI机制

ConfigCenterServiceLoader是通过SPI机制来进行加载配置中心ConfigCenter的实现类

注册实例

ConfigCenterServiceLoader的静态方法中直接调用了上面我们分析的NewInstanceServiceLoader类的register()方法加载配置 的ConfigCenter的实例,sharding-orchestration-config-zookeeper-curator模块定义的实现类是CuratorZookeeperConfigCenter,sharding-orchestration-config-apollo模块定义的实现类是ApolloConfigCenter

获取实例

ConfigCenterServiceLoader的load()方法是从SPI机制中来加载配置中心实例,调用了它的父类TypeBasedSPIServiceLoader的newService()方法,而这个方法中又是调用NewInstanceServiceLoader的newServiceInstances(classType)方法来获取实例,其中classType是配置中心的类型,这个值在ConfigCenter的不同实现类中值不同。

总结

这篇文章我们讲了ShardingSphere是如何使用Java的SPI机制,列出来SQL解析器和配置中心的两个例子

在使用Java的SPI机制的要注意以下几点:

  1. 不同的功能对应有相同接口的不同实现类可以使用SPI机制
  2. SPI机制中配置文件在resoures文件夹的META-INF/services 目录下,文件名为接口名,文件内容为需要加载的接口的具体实现类的全限定名
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。