You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2018/03/30 08:34:48 UTC
[incubator-servicecomb-java-chassis] 01/04: SCB-447 cache instances
by SPI type
This is an automated email from the ASF dual-hosted git repository.
liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-java-chassis.git
commit 862006574e7cd6d4b6abf964378565b1206146a0
Author: wujimin <wu...@huawei.com>
AuthorDate: Thu Mar 29 13:06:55 2018 +0800
SCB-447 cache instances by SPI type
---
.../foundation/common/utils/SPIServiceUtils.java | 90 +++++++++++++++++-----
.../common/utils/SPIServiceDef0Impl.java | 22 ++++++
.../common/utils/TestSPIServiceUtils.java | 23 ++++++
3 files changed, 114 insertions(+), 21 deletions(-)
diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/SPIServiceUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/SPIServiceUtils.java
index 5011abe..9cbfc86 100644
--- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/SPIServiceUtils.java
+++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/SPIServiceUtils.java
@@ -22,8 +22,10 @@ import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
+import java.util.Map;
import java.util.Map.Entry;
import java.util.ServiceLoader;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import org.slf4j.Logger;
@@ -38,31 +40,21 @@ import org.springframework.util.ReflectionUtils;
public final class SPIServiceUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(SPIServiceUtils.class);
+ // load one service, maybe trigger load another service
+ // computeIfAbsent can not support this feature
+ // so use double check
+ private static final Object LOCK = new Object();
+
+ private static final Map<Class<?>, List<Object>> cache = new ConcurrentHashMap<>();
+
private SPIServiceUtils() {
}
/**
- * get target service.if target services are array,only random access to a service.
+ * no cache, return new instances every time.
*/
- public static <T> T getTargetService(Class<T> serviceType) {
- ServiceLoader<T> loader = ServiceLoader.load(serviceType);
- for (T service : loader) {
- LOGGER.info("get the SPI service success, the extend service is: {}", service.getClass());
- return service;
- }
- LOGGER.info("Can not get the SPI service, the interface type is: {}", serviceType.toString());
- return null;
- }
-
- public static <T> List<T> getAllService(Class<T> serviceType) {
- List<T> list = new ArrayList<>();
- ServiceLoader.load(serviceType).forEach(list::add);
-
- return list;
- }
-
- public static <T> List<T> getSortedService(Class<T> serviceType) {
+ public static <T> List<T> loadSortedService(Class<T> serviceType) {
List<Entry<Integer, T>> serviceEntries = new ArrayList<>();
ServiceLoader<T> serviceLoader = ServiceLoader.load(serviceType);
serviceLoader.forEach(service -> {
@@ -76,18 +68,74 @@ public final class SPIServiceUtils {
serviceEntries.add(entry);
});
- return serviceEntries.stream()
+ List<T> services = serviceEntries.stream()
.sorted(Comparator.comparingInt(Entry::getKey))
.map(Entry::getValue)
.collect(Collectors.toList());
+
+ LOGGER.info("Found SPI service {}, count={}.", serviceType.getName(), services.size());
+ for (int idx = 0; idx < services.size(); idx++) {
+ T service = services.get(idx);
+ LOGGER.info(" {}. {}.", idx, service.getClass().getName());
+ }
+
+ return services;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> List<T> getOrLoadSortedService(Class<T> serviceType) {
+ List<Object> services = cache.get(serviceType);
+ if (services == null) {
+ synchronized (LOCK) {
+ services = cache.get(serviceType);
+ if (services == null) {
+ services = (List<Object>) loadSortedService(serviceType);
+ cache.put(serviceType, services);
+ }
+ }
+ }
+
+ return (List<T>) services;
+ }
+
+ /**
+ * get target service.if target services are array,only random access to a service.
+ */
+ public static <T> T getTargetService(Class<T> serviceType) {
+ List<T> services = getOrLoadSortedService(serviceType);
+ if (services.isEmpty()) {
+ LOGGER.info("Can not find SPI service for {}", serviceType.getName());
+ return null;
+ }
+
+ return services.get(0);
+ }
+
+ public static <T> List<T> getAllService(Class<T> serviceType) {
+ return getOrLoadSortedService(serviceType);
+ }
+
+ public static <T> List<T> getSortedService(Class<T> serviceType) {
+ return getOrLoadSortedService(serviceType);
}
public static <T> T getPriorityHighestService(Class<T> serviceType) {
- List<T> services = getSortedService(serviceType);
+ List<T> services = getOrLoadSortedService(serviceType);
if (services.isEmpty()) {
+ LOGGER.info("Can not find SPI service for {}", serviceType.getName());
return null;
}
return services.get(0);
}
+
+ @SuppressWarnings("unchecked")
+ public static <T, IMPL> IMPL getTargetService(Class<T> serviceType, Class<IMPL> implType) {
+ List<T> services = getOrLoadSortedService(serviceType);
+ return (IMPL) services
+ .stream()
+ .filter(service -> service.getClass().equals(implType))
+ .findFirst()
+ .orElse(null);
+ }
}
diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/SPIServiceDef0Impl.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/SPIServiceDef0Impl.java
new file mode 100644
index 0000000..08cd5a3
--- /dev/null
+++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/SPIServiceDef0Impl.java
@@ -0,0 +1,22 @@
+/*
+ * 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.servicecomb.foundation.common.utils;
+
+public class SPIServiceDef0Impl implements SPIServiceDef0 {
+
+}
diff --git a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestSPIServiceUtils.java b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestSPIServiceUtils.java
index 24e81bf..2bb136b 100644
--- a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestSPIServiceUtils.java
+++ b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/utils/TestSPIServiceUtils.java
@@ -18,6 +18,7 @@
package org.apache.servicecomb.foundation.common.utils;
import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
@@ -46,6 +47,19 @@ public class TestSPIServiceUtils {
public void testGetTargetServiceNotNull() {
SPIServiceDef service = SPIServiceUtils.getTargetService(SPIServiceDef.class);
Assert.assertTrue(SPIServiceDef.class.isInstance(service));
+
+ Assert.assertSame(service, SPIServiceUtils.getTargetService(SPIServiceDef.class));
+ }
+
+ @Test
+ public void testGetTargetService_special_null() {
+ Assert.assertNull(SPIServiceUtils.getTargetService(SPIServiceDef0.class, SPIServiceDef0Impl.class));
+ }
+
+ @Test
+ public void testGetTargetService_special_notNull() {
+ SPIServiceDef service = SPIServiceUtils.getTargetService(SPIServiceDef.class, SPIServiceDefImpl.class);
+ Assert.assertTrue(SPIServiceDefImpl.class.isInstance(service));
}
@Test
@@ -68,6 +82,15 @@ public class TestSPIServiceUtils {
};
Assert.assertThat(SPIServiceUtils.getSortedService(Ordered.class), Matchers.contains(o1, o2));
+ Assert.assertThat(SPIServiceUtils.getAllService(Ordered.class), Matchers.contains(o1, o2));
Assert.assertThat(SPIServiceUtils.getPriorityHighestService(Ordered.class), Matchers.is(o1));
+
+ Map<Class<?>, List<Object>> cache = Deencapsulation.getField(SPIServiceUtils.class, "cache");
+ cache.clear();
+ }
+
+ @Test
+ public void getPriorityHighestService_null() {
+ Assert.assertNull(SPIServiceUtils.getPriorityHighestService(SPIServiceDef0.class));
}
}
--
To stop receiving notification emails like this one, please contact
liubao@apache.org.