This is an automated email from the ASF dual-hosted git repository.
chengzhang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new f1bc9413622 Refactor OrderedSPILoader and RuleMetadata for improved
performance (#37972)
f1bc9413622 is described below
commit f1bc9413622e580f60f8bd27e2daeaf604582bab
Author: Cong Hu <[email protected]>
AuthorDate: Fri Feb 6 18:09:17 2026 +0800
Refactor OrderedSPILoader and RuleMetadata for improved performance (#37972)
---
.../infra/metadata/database/rule/RuleMetaData.java | 130 +++++++++++--
.../infra/spi/type/ordered/OrderedSPILoader.java | 205 ++++++++++++++++++---
.../spi/type/ordered/OrderedSPILoaderTest.java | 37 ++++
.../fixture/OrderedSPINonSingletonFixture.java | 23 +++
.../impl/OrderedSPINonSingletonFixtureImpl.java | 33 ++++
...e.ordered.fixture.OrderedSPINonSingletonFixture | 18 ++
6 files changed, 402 insertions(+), 44 deletions(-)
diff --git
a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/rule/RuleMetaData.java
b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/rule/RuleMetaData.java
index d6a6b7f10d8..05fbe902fa1 100644
---
a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/rule/RuleMetaData.java
+++
b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/rule/RuleMetaData.java
@@ -17,10 +17,10 @@
package org.apache.shardingsphere.infra.metadata.database.rule;
-import com.google.common.base.Preconditions;
import lombok.Getter;
import org.apache.shardingsphere.infra.config.rule.RuleConfiguration;
import org.apache.shardingsphere.infra.datanode.DataNode;
+import org.apache.shardingsphere.infra.exception.ShardingSpherePreconditions;
import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
import org.apache.shardingsphere.infra.rule.attribute.RuleAttribute;
import
org.apache.shardingsphere.infra.rule.attribute.datanode.DataNodeRuleAttribute;
@@ -34,19 +34,27 @@ import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* Rule meta data.
*/
-@Getter
public final class RuleMetaData {
+ private final Map<Class<?>, Collection<?>> ruleCache = new
ConcurrentHashMap<>();
+
+ private final Map<Class<?>, Optional<ShardingSphereRule>> singleRuleCache
= new ConcurrentHashMap<>();
+
+ private final Map<Class<?>, Collection<?>> attributeCache = new
ConcurrentHashMap<>();
+
+ @Getter
private final Collection<ShardingSphereRule> rules;
public RuleMetaData(final Collection<ShardingSphereRule> rules) {
- this.rules = new CopyOnWriteArrayList<>(rules);
+ this.rules = new CacheInvalidatingCopyOnWriteArrayList(rules);
}
/**
@@ -65,11 +73,20 @@ public final class RuleMetaData {
* @param <T> type of rule
* @return found rules
*/
+ @SuppressWarnings("unchecked")
public <T extends ShardingSphereRule> Collection<T> findRules(final
Class<T> clazz) {
- Collection<T> result = new LinkedList<>();
+ Collection<?> result = ruleCache.get(clazz);
+ if (null == result) {
+ result = ruleCache.computeIfAbsent(clazz, this::computeRules);
+ }
+ return (Collection<T>) result;
+ }
+
+ private Collection<? extends ShardingSphereRule> computeRules(final
Class<?> clazz) {
+ Collection<ShardingSphereRule> result = new LinkedList<>();
for (ShardingSphereRule each : rules) {
if (clazz.isAssignableFrom(each.getClass())) {
- result.add(clazz.cast(each));
+ result.add(each);
}
}
return result;
@@ -82,9 +99,13 @@ public final class RuleMetaData {
* @param <T> type of rule
* @return found single rule
*/
+ @SuppressWarnings("unchecked")
public <T extends ShardingSphereRule> Optional<T> findSingleRule(final
Class<T> clazz) {
- Collection<T> foundRules = findRules(clazz);
- return foundRules.isEmpty() ? Optional.empty() :
Optional.of(foundRules.iterator().next());
+ Optional<ShardingSphereRule> result = singleRuleCache.get(clazz);
+ if (null == result) {
+ result = singleRuleCache.computeIfAbsent(clazz,
this::computeSingleRule);
+ }
+ return (Optional<T>) result;
}
/**
@@ -94,10 +115,21 @@ public final class RuleMetaData {
* @param <T> type of rule
* @return found single rule
*/
+ @SuppressWarnings("unchecked")
public <T extends ShardingSphereRule> T getSingleRule(final Class<T>
clazz) {
- 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();
+ Optional<ShardingSphereRule> shardingSphereRule =
singleRuleCache.get(clazz);
+ if (null == shardingSphereRule) {
+ shardingSphereRule = singleRuleCache.computeIfAbsent(clazz,
this::computeSingleRule);
+ }
+ ShardingSpherePreconditions.checkState(shardingSphereRule.isPresent(),
+ () -> new IllegalStateException(String.format("Rule `%s`
should have and only have one instance.", clazz.getSimpleName())));
+ return (T) shardingSphereRule.get();
+ }
+
+ @SuppressWarnings("unchecked")
+ private Optional<ShardingSphereRule> computeSingleRule(final Class<?>
clazz) {
+ Collection<ShardingSphereRule> rules =
findRules((Class<ShardingSphereRule>) clazz);
+ return 1 == rules.size() ? Optional.of(rules.iterator().next()) :
Optional.empty();
}
/**
@@ -166,27 +198,87 @@ public final class RuleMetaData {
* @param <T> type of rule attributes
* @return rule attributes
*/
+ @SuppressWarnings("unchecked")
public <T extends RuleAttribute> Collection<T> getAttributes(final
Class<T> attributeClass) {
- Collection<T> result = new LinkedList<>();
+ Collection<?> result = attributeCache.get(attributeClass);
+ if (null == result) {
+ result = attributeCache.computeIfAbsent(attributeClass,
this::computeAttributes);
+ }
+ return (Collection<T>) result;
+ }
+
+ private Collection<? extends RuleAttribute> computeAttributes(final
Class<?> attributeClass) {
+ Collection<RuleAttribute> result = new LinkedList<>();
for (ShardingSphereRule each : rules) {
-
each.getAttributes().findAttribute(attributeClass).ifPresent(result::add);
+
each.getAttributes().findAttribute(attributeClass.asSubclass(RuleAttribute.class)).ifPresent(result::add);
}
return result;
}
/**
- * Get rule attributes.
+ * Find rule attribute.
*
* @param attributeClass rule attribute class
* @param <T> type of rule attributes
- * @return rule attributes
+ * @return rule attribute
*/
public <T extends RuleAttribute> Optional<T> findAttribute(final Class<T>
attributeClass) {
- for (ShardingSphereRule each : rules) {
- if
(each.getAttributes().findAttribute(attributeClass).isPresent()) {
- return each.getAttributes().findAttribute(attributeClass);
- }
+ Collection<T> attributes = getAttributes(attributeClass);
+ return attributes.isEmpty() ? Optional.empty() :
Optional.of(attributes.iterator().next());
+ }
+
+ private final class CacheInvalidatingCopyOnWriteArrayList extends
CopyOnWriteArrayList<ShardingSphereRule> {
+
+ CacheInvalidatingCopyOnWriteArrayList(final
Collection<ShardingSphereRule> rules) {
+ super(rules);
+ }
+
+ private void invalidateCache() {
+ ruleCache.clear();
+ singleRuleCache.clear();
+ attributeCache.clear();
+ }
+
+ @Override
+ public boolean add(final ShardingSphereRule rule) {
+ invalidateCache();
+ return super.add(rule);
+ }
+
+ @Override
+ public boolean addAll(final Collection<? extends ShardingSphereRule>
collection) {
+ invalidateCache();
+ return super.addAll(collection);
+ }
+
+ @Override
+ public boolean remove(final Object o) {
+ invalidateCache();
+ return super.remove(o);
+ }
+
+ @Override
+ public boolean removeAll(final Collection<?> objects) {
+ invalidateCache();
+ return super.removeAll(objects);
+ }
+
+ @Override
+ public boolean removeIf(final Predicate<? super ShardingSphereRule>
filter) {
+ invalidateCache();
+ return super.removeIf(filter);
+ }
+
+ @Override
+ public boolean retainAll(final Collection<?> objects) {
+ invalidateCache();
+ return super.retainAll(objects);
+ }
+
+ @Override
+ public void clear() {
+ invalidateCache();
+ super.clear();
}
- return Optional.empty();
}
}
diff --git
a/infra/spi/src/main/java/org/apache/shardingsphere/infra/spi/type/ordered/OrderedSPILoader.java
b/infra/spi/src/main/java/org/apache/shardingsphere/infra/spi/type/ordered/OrderedSPILoader.java
index 077a7005ce1..e58bcb819ac 100644
---
a/infra/spi/src/main/java/org/apache/shardingsphere/infra/spi/type/ordered/OrderedSPILoader.java
+++
b/infra/spi/src/main/java/org/apache/shardingsphere/infra/spi/type/ordered/OrderedSPILoader.java
@@ -21,14 +21,22 @@ import com.google.common.base.Preconditions;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.shardingsphere.infra.spi.ShardingSphereServiceLoader;
-import
org.apache.shardingsphere.infra.spi.type.ordered.cache.OrderedServicesCache;
+import org.apache.shardingsphere.infra.spi.annotation.SingletonSPI;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
-import java.util.Optional;
+import java.util.Map.Entry;
+import java.util.Set;
import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
/**
* Ordered SPI loader.
@@ -36,6 +44,14 @@ import java.util.TreeMap;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class OrderedSPILoader {
+ private static final ClassValue<OrderedSPIRegistry<?>> REGISTRY = new
ClassValue<OrderedSPIRegistry<?>>() {
+
+ @Override
+ protected OrderedSPIRegistry<?> computeValue(final Class<?> clazz) {
+ return null != clazz.getAnnotation(SingletonSPI.class) ? new
CachedSingletonOrderedSPIRegistry<>(clazz) : new
NoCachePrototypeOrderedSPIRegistry<>(clazz);
+ }
+ };
+
/**
* Get services by class type.
*
@@ -44,13 +60,9 @@ public final class OrderedSPILoader {
* @param <T> type of ordered SPI class
* @return got services
*/
+ @SuppressWarnings("unchecked")
public static <T extends OrderedSPI<?>> Map<Class<?>, T>
getServicesByClass(final Class<T> serviceInterface, final Collection<Class<?>>
types) {
- Collection<T> services = getServices(serviceInterface);
- Map<Class<?>, T> result = new LinkedHashMap<>(services.size(), 1F);
- for (T each : services) {
- types.stream().filter(type -> each.getTypeClass() ==
type).forEach(type -> result.put(type, each));
- }
- return result;
+ return ((OrderedSPIRegistry<T>)
REGISTRY.get(serviceInterface)).getServicesByClass(types);
}
/**
@@ -62,8 +74,9 @@ public final class OrderedSPILoader {
* @param <V> type of ordered SPI class
* @return got services
*/
+ @SuppressWarnings("unchecked")
public static <K, V extends OrderedSPI<?>> Map<K, V> getServices(final
Class<V> serviceInterface, final Collection<K> types) {
- return getServices(serviceInterface, types, Comparator.naturalOrder());
+ return ((OrderedSPIRegistry<V>)
REGISTRY.get(serviceInterface)).getServices(types);
}
/**
@@ -78,16 +91,12 @@ public final class OrderedSPILoader {
*/
@SuppressWarnings("unchecked")
public static <K, V extends OrderedSPI<?>> Map<K, V> getServices(final
Class<V> serviceInterface, final Collection<K> types, final Comparator<Integer>
orderComparator) {
- Optional<Map<K, V>> cachedServices =
OrderedServicesCache.findCachedServices(serviceInterface, types).map(optional
-> (Map<K, V>) optional);
- if (cachedServices.isPresent()) {
- return cachedServices.get();
+ List<Entry<K, V>> orderServices = new
ArrayList<>(((OrderedSPIRegistry<V>)
REGISTRY.get(serviceInterface)).getServices(types).entrySet());
+ orderServices.sort((e1, e2) ->
orderComparator.compare(e1.getValue().getOrder(), e2.getValue().getOrder()));
+ Map<K, V> result = new LinkedHashMap<>(orderServices.size(), 1F);
+ for (Entry<K, V> entry : orderServices) {
+ result.put(entry.getKey(), entry.getValue());
}
- Collection<V> services = getServices(serviceInterface,
orderComparator);
- Map<K, V> result = new LinkedHashMap<>(services.size(), 1F);
- for (V each : services) {
- types.stream().filter(type -> each.getTypeClass() ==
type.getClass()).forEach(type -> result.put(type, each));
- }
- OrderedServicesCache.cacheServices(serviceInterface, types, result);
return result;
}
@@ -98,16 +107,162 @@ public final class OrderedSPILoader {
* @param <T> type of ordered SPI class
* @return got services
*/
+ @SuppressWarnings("unchecked")
public static <T extends OrderedSPI<?>> Collection<T> getServices(final
Class<T> serviceInterface) {
- return getServices(serviceInterface, Comparator.naturalOrder());
+ return ((OrderedSPIRegistry<T>)
REGISTRY.get(serviceInterface)).getOrderedServices();
+ }
+
+ private interface OrderedSPIRegistry<T extends OrderedSPI<?>> {
+
+ Collection<T> getOrderedServices();
+
+ Map<Class<?>, T> getServicesByClass(Collection<Class<?>> types);
+
+ <K> Map<K, T> getServices(Collection<K> types);
+ }
+
+ private static final class CachedSingletonOrderedSPIRegistry<T extends
OrderedSPI<?>> implements OrderedSPIRegistry<T> {
+
+ private final Collection<T> orderedServices;
+
+ private final Map<Class<?>, T> singleTypeClassToService;
+
+ private final Map<Set<Class<?>>, Map<Class<?>, T>>
multiTypeClassToServices = new ConcurrentHashMap<>();
+
+ private final Map<Collection<?>, Map<?, T>> multiObjectToServices =
new ConcurrentHashMap<>();
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ CachedSingletonOrderedSPIRegistry(final Class<?> serviceInterface) {
+ Map<Integer, T> orderServices = new
TreeMap<>(Comparator.naturalOrder());
+ for (Object each :
ShardingSphereServiceLoader.getServiceInstances((Class) serviceInterface)) {
+ Preconditions.checkArgument(!orderServices.containsKey(((T)
each).getOrder()),
+ "Found same order `%s` with `%s` and `%s`", ((T)
each).getOrder(), orderServices.get(((T) each).getOrder()), each);
+ orderServices.put(((T) each).getOrder(), (T) each);
+ }
+ orderedServices = orderServices.values();
+ singleTypeClassToService = new HashMap<>(orderedServices.size(),
1F);
+ for (T each : orderedServices) {
+ singleTypeClassToService.put(each.getTypeClass(), each);
+ }
+ }
+
+ @Override
+ public Collection<T> getOrderedServices() {
+ return orderedServices;
+ }
+
+ @Override
+ public Map<Class<?>, T> getServicesByClass(final Collection<Class<?>>
types) {
+ if (1 == types.size()) {
+ Class<?> type = types.iterator().next();
+ T service = singleTypeClassToService.get(type);
+ return null == service ? Collections.emptyMap() :
Collections.singletonMap(type, service);
+ }
+ Set<Class<?>> typeClasses = types instanceof Set ? (Set<Class<?>>)
types : new HashSet<>(types);
+ Map<Class<?>, T> result =
multiTypeClassToServices.get(typeClasses);
+ if (null == result) {
+ result = multiTypeClassToServices.computeIfAbsent(typeClasses,
this::computeServicesByClass);
+ }
+ return result;
+ }
+
+ private Map<Class<?>, T> computeServicesByClass(final Set<Class<?>>
types) {
+ Map<Class<?>, T> result = new LinkedHashMap<>(types.size(), 1F);
+ for (T each : orderedServices) {
+ if (types.contains(each.getTypeClass())) {
+ result.put(each.getTypeClass(), each);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <K> Map<K, T> getServices(final Collection<K> types) {
+ if (1 == types.size()) {
+ K type = types.iterator().next();
+ T service = singleTypeClassToService.get(type.getClass());
+ return null == service ? Collections.emptyMap() :
Collections.singletonMap(type, service);
+ }
+ Map<?, T> result = multiObjectToServices.get(types);
+ if (null == result) {
+ result = multiObjectToServices.computeIfAbsent(types, t ->
computeServicesByObject((Collection<Object>) t));
+ }
+ return (Map<K, T>) result;
+ }
+
+ private Map<Object, T> computeServicesByObject(final
Collection<Object> types) {
+ Map<Class<?>, List<Object>> classTypeMap = new
HashMap<>(types.size(), 1F);
+ Set<Class<?>> typeClasses = new HashSet<>(types.size(), 1F);
+ for (Object each : types) {
+ classTypeMap.computeIfAbsent(each.getClass(), clazz -> new
LinkedList<>()).add(each);
+ typeClasses.add(each.getClass());
+ }
+ Map<Object, T> result = new LinkedHashMap<>(types.size(), 1F);
+ for (T each : orderedServices) {
+ if (typeClasses.contains(each.getTypeClass())) {
+ for (Object type : classTypeMap.get(each.getTypeClass())) {
+ result.put(type, each);
+ }
+ }
+ }
+ return result;
+ }
}
- private static <T extends OrderedSPI<?>> Collection<T> getServices(final
Class<T> serviceInterface, final Comparator<Integer> comparator) {
- Map<Integer, T> result = new TreeMap<>(comparator);
- for (T each :
ShardingSphereServiceLoader.getServiceInstances(serviceInterface)) {
- Preconditions.checkArgument(!result.containsKey(each.getOrder()),
"Found same order `%s` with `%s` and `%s`", each.getOrder(),
result.get(each.getOrder()), each);
- result.put(each.getOrder(), each);
+ private static final class NoCachePrototypeOrderedSPIRegistry<T extends
OrderedSPI<?>> implements OrderedSPIRegistry<T> {
+
+ private final Class<T> serviceInterface;
+
+ @SuppressWarnings("unchecked")
+ NoCachePrototypeOrderedSPIRegistry(final Class<?> serviceInterface) {
+ this.serviceInterface = (Class<T>) serviceInterface;
+ }
+
+ @Override
+ public Collection<T> getOrderedServices() {
+ return loadOrderedServices();
+ }
+
+ @Override
+ public Map<Class<?>, T> getServicesByClass(final Collection<Class<?>>
types) {
+ Set<Class<?>> typeClasses = types instanceof Set ? (Set<Class<?>>)
types : new HashSet<>(types);
+ Map<Class<?>, T> result = new LinkedHashMap<>(types.size(), 1F);
+ for (T each : loadOrderedServices()) {
+ if (typeClasses.contains(each.getTypeClass())) {
+ result.put(each.getTypeClass(), each);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public <K> Map<K, T> getServices(final Collection<K> types) {
+ Map<Class<?>, List<K>> classTypeMap = new HashMap<>(types.size(),
1F);
+ Set<Class<?>> typeClasses = new HashSet<>(types.size(), 1F);
+ for (K each : types) {
+ classTypeMap.computeIfAbsent(each.getClass(), clazz -> new
LinkedList<>()).add(each);
+ typeClasses.add(each.getClass());
+ }
+ Map<K, T> result = new LinkedHashMap<>(types.size(), 1F);
+ for (T each : loadOrderedServices()) {
+ if (typeClasses.contains(each.getTypeClass())) {
+ for (K type : classTypeMap.get(each.getTypeClass())) {
+ result.put(type, each);
+ }
+ }
+ }
+ return result;
+ }
+
+ private Collection<T> loadOrderedServices() {
+ Map<Integer, T> result = new TreeMap<>(Comparator.naturalOrder());
+ for (T each :
ShardingSphereServiceLoader.getServiceInstances(serviceInterface)) {
+
Preconditions.checkArgument(!result.containsKey(each.getOrder()),
+ "Found same order `%s` with `%s` and `%s`",
each.getOrder(), result.get(each.getOrder()), each);
+ result.put(each.getOrder(), each);
+ }
+ return result.values();
}
- return result.values();
}
}
diff --git
a/infra/spi/src/test/java/org/apache/shardingsphere/infra/spi/type/ordered/OrderedSPILoaderTest.java
b/infra/spi/src/test/java/org/apache/shardingsphere/infra/spi/type/ordered/OrderedSPILoaderTest.java
index d6a45753d84..e31cef34060 100644
---
a/infra/spi/src/test/java/org/apache/shardingsphere/infra/spi/type/ordered/OrderedSPILoaderTest.java
+++
b/infra/spi/src/test/java/org/apache/shardingsphere/infra/spi/type/ordered/OrderedSPILoaderTest.java
@@ -17,6 +17,7 @@
package org.apache.shardingsphere.infra.spi.type.ordered;
+import
org.apache.shardingsphere.infra.spi.type.ordered.fixture.OrderedSPINonSingletonFixture;
import
org.apache.shardingsphere.infra.spi.type.ordered.cache.OrderedServicesCache;
import
org.apache.shardingsphere.infra.spi.type.ordered.fixture.OrderedInterfaceFixture;
import
org.apache.shardingsphere.infra.spi.type.ordered.fixture.OrderedSPIFixture;
@@ -32,6 +33,8 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.sameInstance;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.isA;
@@ -66,4 +69,38 @@ class OrderedSPILoaderTest {
assertThat(OrderedSPILoader.getServices(OrderedSPIFixture.class,
Collections.singleton(key)),
is(OrderedSPILoader.getServices(OrderedSPIFixture.class,
Collections.singleton(key))));
}
+
+ @SuppressWarnings("rawtypes")
+ @Test
+ void assertGetServicesByClassWithSingletonSPIReturnsSameInstance() {
+ Map<Class<?>, OrderedSPIFixture> firstCall =
OrderedSPILoader.getServicesByClass(OrderedSPIFixture.class,
Collections.singleton(OrderedInterfaceFixtureImpl.class));
+ Map<Class<?>, OrderedSPIFixture> secondCall =
OrderedSPILoader.getServicesByClass(OrderedSPIFixture.class,
Collections.singleton(OrderedInterfaceFixtureImpl.class));
+ assertThat(firstCall.get(OrderedInterfaceFixtureImpl.class),
is(sameInstance(secondCall.get(OrderedInterfaceFixtureImpl.class))));
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Test
+ void assertGetServicesWithSingletonSPIReturnsSameInstance() {
+ OrderedInterfaceFixtureImpl key = new OrderedInterfaceFixtureImpl();
+ Map<OrderedInterfaceFixtureImpl, OrderedSPIFixture> firstCall =
OrderedSPILoader.getServices(OrderedSPIFixture.class,
Collections.singleton(key));
+ Map<OrderedInterfaceFixtureImpl, OrderedSPIFixture> secondCall =
OrderedSPILoader.getServices(OrderedSPIFixture.class,
Collections.singleton(key));
+ assertThat(firstCall.get(key), is(sameInstance(secondCall.get(key))));
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Test
+ void
assertGetServicesByClassWithNonSingletonSPIReturnsDifferentInstances() {
+ Map<Class<?>, OrderedSPINonSingletonFixture> firstCall =
OrderedSPILoader.getServicesByClass(OrderedSPINonSingletonFixture.class,
Collections.singleton(OrderedInterfaceFixtureImpl.class));
+ Map<Class<?>, OrderedSPINonSingletonFixture> secondCall =
OrderedSPILoader.getServicesByClass(OrderedSPINonSingletonFixture.class,
Collections.singleton(OrderedInterfaceFixtureImpl.class));
+ assertThat(firstCall.get(OrderedInterfaceFixtureImpl.class),
is(not(sameInstance(secondCall.get(OrderedInterfaceFixtureImpl.class)))));
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Test
+ void assertGetServicesWithNonSingletonSPIReturnsDifferentInstances() {
+ OrderedInterfaceFixtureImpl key = new OrderedInterfaceFixtureImpl();
+ Map<OrderedInterfaceFixtureImpl, OrderedSPINonSingletonFixture>
firstCall = OrderedSPILoader.getServices(OrderedSPINonSingletonFixture.class,
Collections.singleton(key));
+ Map<OrderedInterfaceFixtureImpl, OrderedSPINonSingletonFixture>
secondCall = OrderedSPILoader.getServices(OrderedSPINonSingletonFixture.class,
Collections.singleton(key));
+ assertThat(firstCall.get(key),
is(not(sameInstance(secondCall.get(key)))));
+ }
}
diff --git
a/infra/spi/src/test/java/org/apache/shardingsphere/infra/spi/type/ordered/fixture/OrderedSPINonSingletonFixture.java
b/infra/spi/src/test/java/org/apache/shardingsphere/infra/spi/type/ordered/fixture/OrderedSPINonSingletonFixture.java
new file mode 100644
index 00000000000..53d8e2dffd9
--- /dev/null
+++
b/infra/spi/src/test/java/org/apache/shardingsphere/infra/spi/type/ordered/fixture/OrderedSPINonSingletonFixture.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.infra.spi.type.ordered.fixture;
+
+import org.apache.shardingsphere.infra.spi.type.ordered.OrderedSPI;
+
+public interface OrderedSPINonSingletonFixture<T> extends OrderedSPI<T> {
+}
diff --git
a/infra/spi/src/test/java/org/apache/shardingsphere/infra/spi/type/ordered/fixture/impl/OrderedSPINonSingletonFixtureImpl.java
b/infra/spi/src/test/java/org/apache/shardingsphere/infra/spi/type/ordered/fixture/impl/OrderedSPINonSingletonFixtureImpl.java
new file mode 100644
index 00000000000..9a3dd743287
--- /dev/null
+++
b/infra/spi/src/test/java/org/apache/shardingsphere/infra/spi/type/ordered/fixture/impl/OrderedSPINonSingletonFixtureImpl.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.infra.spi.type.ordered.fixture.impl;
+
+import
org.apache.shardingsphere.infra.spi.type.ordered.fixture.OrderedSPINonSingletonFixture;
+
+public final class OrderedSPINonSingletonFixtureImpl implements
OrderedSPINonSingletonFixture<OrderedInterfaceFixtureImpl> {
+
+ @Override
+ public Class<OrderedInterfaceFixtureImpl> getTypeClass() {
+ return OrderedInterfaceFixtureImpl.class;
+ }
+
+ @Override
+ public int getOrder() {
+ return 1;
+ }
+}
diff --git
a/infra/spi/src/test/resources/META-INF/services/org.apache.shardingsphere.infra.spi.type.ordered.fixture.OrderedSPINonSingletonFixture
b/infra/spi/src/test/resources/META-INF/services/org.apache.shardingsphere.infra.spi.type.ordered.fixture.OrderedSPINonSingletonFixture
new file mode 100644
index 00000000000..d396cdccd4c
--- /dev/null
+++
b/infra/spi/src/test/resources/META-INF/services/org.apache.shardingsphere.infra.spi.type.ordered.fixture.OrderedSPINonSingletonFixture
@@ -0,0 +1,18 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.apache.shardingsphere.infra.spi.type.ordered.fixture.impl.OrderedSPINonSingletonFixtureImpl