When I try to obtain an instance of a Class through ServiceLoader on a TaskManager node the class cannot be loaded, basically I cannot access the classes declared in META-INF/services via ServiceLoader at Runtime.
I am using ShardignSphere to broadcast some data from the database, but the framework relies on some dependencies being loaded by the Java SPI, is there any way to solve the problem? In previous versions (4.x.x) I used to do it with Reflection but with the new version of ShardingSphere (5.3.1) there would be too many things that need to be loaded and it wouldn't be feasible, what's the correct way to do this?
EDIT:
ShardingSphere stackTrace: this is the first occurrence of a precontition check where a Class that is supposed to be loaded via SPI isn't loaded.
Collection<T> foundRules = findRules(clazz);
Preconditions.checkState(1 == foundRules.size(), "Rule `%s` should have and only have one instance.", clazz.getSimpleName());
return foundRules.iterator().next();
java.lang.IllegalStateException: Rule `TrafficRule` should have and only have one instance.
at com.google.common.base.Preconditions.checkState(Preconditions.java:591)
at org.apache.shardingsphere.infra.metadata.database.rule.ShardingSphereRuleMetaData.getSingleRule(ShardingSphereRuleMetaData.java:91)
at org.apache.shardingsphere.driver.jdbc.core.connection.ConnectionManager.getTrafficDataSourceMap(ConnectionManager.java:88)
at org.apache.shardingsphere.driver.jdbc.core.connection.ConnectionManager.<init>(ConnectionManager.java:82)
at org.apache.shardingsphere.driver.jdbc.core.connection.ShardingSphereConnection.<init>(ShardingSphereConnection.java:71)
at org.apache.shardingsphere.driver.state.ok.OKDriverState.getConnection(OKDriverState.java:34)
at org.apache.shardingsphere.driver.state.DriverStateContext.getConnection(DriverStateContext.java:44)
at org.apache.shardingsphere.driver.jdbc.core.datasource.ShardingSphereDataSource.getConnection(ShardingSphereDataSource.java:86)
at com.huawei.networkops.flink.monitor.pingmesh.broadcast.PingmeshDataResolver.update(PingmeshDataResolver.java:77)
at com.huawei.networkops.flink.monitor.pingmesh.processor.PingmeshDBSourceProcessor$PingmeshBroadcastDataBuilder.buildBroadcastData(PingmeshDBSourceProcessor.java:39)
at com.huawei.networkops.flink.monitor.pingmesh.processor.PingmeshDBSourceProcessor$PingmeshBroadcastDataBuilder.buildBroadcastData(PingmeshDBSourceProcessor.java:30)
at com.huawei.networkops.flink.monitor.common.broadcast.AbstractDataBroadcastStreamProcessor$DataBroadcastFunction.run(AbstractDataBroadcastStreamProcessor.java:166)
at org.apache.flink.streaming.api.operators.StreamSource.run(StreamSource.java:94)
at org.apache.flink.streaming.api.operators.StreamSource.run(StreamSource.java:58)
at org.apache.flink.streaming.runtime.tasks.SourceStreamTask.run(SourceStreamTask.java:99)
at org.apache.flink.streaming.runtime.tasks.StreamTask.invoke(StreamTask.java:300)
at org.apache.flink.runtime.taskmanager.Task.run(Task.java:704)
at java.lang.Thread.run(Thread.java:748)
This is how ShardignSphere SPI loads its dependencies:
private Collection<T> load() {
Collection<T> result = new LinkedList<>();
for (T each : ServiceLoader.load(serviceInterface)) {
result.add(each);
}
return result;
}
public final class ShardingSphereServiceLoader<T> {
private static final Map<Class<?>, ShardingSphereServiceLoader<?>> LOADERS = new ConcurrentHashMap<>();
private final Class<T> serviceInterface;
@Getter
private final Collection<T> services;
private ShardingSphereServiceLoader(final Class<T> serviceInterface) {
this.serviceInterface = serviceInterface;
validate();
services = load();
}
private void validate() {
Preconditions.checkNotNull(serviceInterface, "SPI interface is null.");
Preconditions.checkArgument(serviceInterface.isInterface(), "SPI interface `%s` is not interface.", serviceInterface);
}
private Collection<T> load() {
Collection<T> result = new LinkedList<>();
for (T each : ServiceLoader.load(serviceInterface)) {
result.add(each);
}
return result;
}
/**
* Get service instances.
*
* @param serviceInterface service interface
* @param <T> type of service interface
* @return service instances
* @see <a href="https://bugs.openjdk.java.net/browse/JDK-8161372">JDK-8161372</a>
*/
@SuppressWarnings("unchecked")
public static <T> Collection<T> getServiceInstances(final Class<T> serviceInterface) {
ShardingSphereServiceLoader<?> result = LOADERS.get(serviceInterface);
return (Collection<T>) (null != result ? result.getServiceInstances() : LOADERS.computeIfAbsent(serviceInterface, ShardingSphereServiceLoader::new).getServiceInstances());
}
private Collection<T> getServiceInstances() {
return null == serviceInterface.getAnnotation(SingletonSPI.class) ? createNewServiceInstances() : getSingletonServiceInstances();
}
@SneakyThrows(ReflectiveOperationException.class)
@SuppressWarnings("unchecked")
private Collection<T> createNewServiceInstances() {
Collection<T> result = new LinkedList<>();
for (Object each : services) {
result.add((T) each.getClass().getDeclaredConstructor().newInstance());
}
return result;
}
private Collection<T> getSingletonServiceInstances() {
return services;
}
}