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机制的要注意以下几点:
- 不同的功能对应有相同接口的不同实现类可以使用SPI机制
- SPI机制中配置文件在resoures文件夹的META-INF/services 目录下,文件名为接口名,文件内容为需要加载的接口的具体实现类的全限定名
❤️ 感谢大家
如果你觉得这篇内容对你挺有有帮助的话:
- 欢迎关注我❤️,点赞 标签:service,SQLParserEntry,sql,each,SPI,实例,ShardingSphere,机制 From: https://blog.51cto.com/u_15460453/5757959