org.apache.shardingsphere.spi.exception.ServiceProviderNotFoundException:
No implementation class load from SPI `org.apache.shardingsphere.readwritesplitting.spi.ReplicaLoadBalanceAlgorithm` with type `null`.
从报错信息可以确认是配置文件读取为空导致的异常
排查配置文件是否配置正确,如yml缩进是否正确,字段大小写是否正确
由于配置文件都是官网直接copy,不应该会出现问题,但是坑的是我只copy了具体的某项配置,比如下面配置模式相关参数:
官网直接给的配置是具体某项的配置,并没有给具体的前缀
mode:
type: Memory
而我的前缀(spring.sharding-sphere)是IDEA智能提示出来的,如下,使用了中划线的写法,
spring:
sharding-sphere:
mode:
type: Memory
sharding-sphere
不能使用中划线写法,会导致读取配置文件数据失败,造成空指针异常
修改 sharding-sphere
为 shardingsphere
即可
查看详细报错信息:
org.apache.shardingsphere.spi.exception.ServiceProviderNotFoundException: No implementation class load from SPI `org.apache.shardingsphere.readwritesplitting.spi.ReplicaLoadBalanceAlgorithm` with type `null`.
at org.apache.shardingsphere.spi.typed.TypedSPIRegistry.getRegisteredService(TypedSPIRegistry.java:76) ~[shardingsphere-spi-5.1.1.jar:5.1.1]
at org.apache.shardingsphere.spring.boot.registry.AbstractAlgorithmProvidedBeanRegistry.lambda$registerBean$2(AbstractAlgorithmProvidedBeanRegistry.java:78) ~[shardingsphere-jdbc-spring-boot-starter-infra-5.1.1.jar:5.1.1]
at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684) ~[na:1.8.0_361]
at org.apache.shardingsphere.spring.boot.registry.AbstractAlgorithmProvidedBeanRegistry.registerBean(AbstractAlgorithmProvidedBeanRegistry.java:77) ~[shardingsphere-jdbc-spring-boot-starter-infra-5.1.1.jar:5.1.1]
at org.apache.shardingsphere.readwritesplitting.spring.boot.algorithm.ReadwriteSplittingAlgorithmProvidedBeanRegistry.postProcessBeanDefinitionRegistry(ReadwriteSplittingAlgorithmProvidedBeanRegistry.java:43) ~[shardingsphere-readwrite-splitting-spring-boot-starter-5.1.1.jar:5.1.1]
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:311) ~[spring-context-5.3.29.jar:5.3.29]
可以看到调用链:
直接在 (TypedSPIRegistry.java:76)行和(AbstractAlgorithmProvidedBeanRegistry.java:78) 行所在的方法打上断点
通过调试,可以看到 程序里是使用 typePrefix = "spring.shardingsphere.rules.readwrite-splitting.load-balancers“
前缀来获取环境配置数据。因为我们配置的前缀是 "spring.sharding-sphere
,所以导致获取的 algorithmType
字段为空。
protected final void registerBean(final String prefix, final Class<T> algorithmClass, final BeanDefinitionRegistry registry) {
boolean existPrefix = PropertyUtil.containPropertyPrefix(environment, prefix);
if (existPrefix) {
// 省略非关键行
Map<String, YamlShardingSphereAlgorithmConfiguration> shardingAlgorithmMap = new LinkedHashMap<>();
keys.forEach(each -> {
// 省略非关键行
String typePrefix = String.join("", prefix, each, TYPE_SUFFIX);
String algorithmType = environment.getProperty(typePrefix); // 返回为空了
config.setType(algorithmType);
shardingAlgorithmMap.put(each, config);
});
ShardingSphereServiceLoader.register(algorithmClass);
shardingAlgorithmMap.forEach((key, algorithmConfiguration) -> {
ShardingSphereAlgorithm algorithm = TypedSPIRegistry.getRegisteredService(algorithmClass, algorithmConfiguration.getType(), algorithmConfiguration.getProps());
// 省略非关键行
});
}
}
接着在(TypedSPIRegistry.java:76)中注册负载均衡相关信息的时候就抛出了空指针异常:
public static <T extends TypedSPI> T getRegisteredService(final Class<T> typedSPIClass, final String type, final Properties props) {
Optional<T> result = findRegisteredService(typedSPIClass, type, props);
if (result.isPresent()) {
return result.get();
}
throw new ServiceProviderNotFoundException(typedSPIClass, type);
}
为什么获取
algorithmType
值得入参一定是spring.shardingsphere
开头的呢?
通过调用链定位到 ReadwriteSplittingAlgorithmProvidedBeanRegistry.java:43
public final class ReadwriteSplittingAlgorithmProvidedBeanRegistry extends AbstractAlgorithmProvidedBeanRegistry<ReplicaLoadBalanceAlgorithm> {
private static final String ALGORITHMS = "spring.shardingsphere.rules.readwrite-splitting.load-balancers.";
public ReadwriteSplittingAlgorithmProvidedBeanRegistry(final Environment environment) {
super(environment);
}
@Override
public void postProcessBeanDefinitionRegistry(final BeanDefinitionRegistry registry) {
registerBean(ALGORITHMS, ReplicaLoadBalanceAlgorithm.class, registry);
}
}
可以看到这个类是继承于AbstractAlgorithmProvidedBeanRegistry类,并且使用 ALGORITHMS
参数调用了父类的registerBean
方法。
同时可以发现 ALGORITHMS
成员常量 使用的是写死的 spring.shardingsphere
前缀,所以最终可以确认是配置写错导致的问题。
路径:org.apache.shardingsphere.spring.boot.prop.SpringBootPropertiesConfiguration
通过对SpringBoot的自动装配原理可以找到 xxxPropertiesConfiguration类,查看前缀是否配置正确即可定位问题
@ConfigurationProperties(
prefix = "spring.shardingsphere"
)
public final class SpringBootPropertiesConfiguration {
}
通过属性配置类源码可以看到,源码中映射了 spring.shardingsphere
前缀,而我们配置的是spring.sharding-sphere:
,如果我们配置的属性前缀和配置类中的映射不一致,就会导致启动失败