You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by ya...@apache.org on 2020/03/09 16:14:49 UTC

[servicecomb-java-chassis] branch master updated (908e20f -> 15cb6a7)

This is an automated email from the ASF dual-hosted git repository.

yaohaishi pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git.


    from 908e20f  [SCB-1737] support ISO 8601 data and time (part2: HIGHWAY)
     new 0b507b4  [SCB-1691] modify instance status change interface
     new d6cbf86  [SCB-1691] Decouple the ServiceRegistry and other modules
     new bf3292b  [SCB-1691] add name for ServiceRegistry
     new 8e1f6bf  [SCB-1691] ServiceRegistryConfig just carries config value
     new a407a98  [SCB-1691] ClientPool can be instantiated
     new 096a43b  [SCB-1691] add RestClientUtil for multiple ServiceRegistryClient instance situation
     new 32cf126  [SCB-1691] add WebsocketClientPool for multiple ServiceRegistryClient instance situation
     new 1a920eb  [SCB-1691] replace RestUtils and WebsocketUtils in ServiceRegistryClientImpl
     new e5d89b5  [SCB-1691] add ServiceRegistryCache
     new d4e8db6  [SCB-1691] ServiceRegistry use serviceRegistryCache
     new 7828f7f  [SCB-1691] RegistryUtils manage multiple ServiceRegistry instances
     new c79d5e1  [SCB-1691] Each ServiceRegistry uses an isolated EventBus
     new b24a037  [SCB-1691] code improve
     new 4abbc6d  [SCB-1691] Each registry client use isolated IpPortManager
     new d2126d3  [SCB-1691] add schema and endpoint into all ServiceRegistry instances
     new bbd7702  [SCB-1691] support multiple TLS enabled sc clusters
     new be1660f  [SCB-1691] turn instance status to DOWN and wait for a period when shutdown
     new 369c578  [SCB-1691] fix CI error
     new 15cb6a7  [SCB-1691] fix according to review opinion

The 19 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../org/apache/servicecomb/core/SCBEngine.java     |  63 ++-
 .../handler/impl/ProducerOperationHandler.java     |   1 -
 .../consumer/MicroserviceReferenceConfig.java      |   2 +-
 .../provider/producer/ProducerBootListener.java    |   9 +-
 .../core/transport/TransportManager.java           |   7 +-
 .../handler/impl/TestSimpleLoadBalanceHandler.java |   5 +-
 .../servicecomb/demo/edge/consumer/Consumer.java   |   2 +-
 .../jaxrs/client/MultiErrorCodeServiceClient.java  |   2 +-
 .../foundation/common/event/SimpleSubscriber.java  |   2 +-
 .../loadbalance/TestLoadBalanceHandler2.java       |  39 +-
 .../loadbalance/TestLoadbalanceHandler.java        |   3 +-
 .../java/org/apache/servicecomb/it/ITUtils.java    |   4 +-
 .../servicecomb/it/deploy/MicroserviceDeploy.java  |   2 +-
 .../it/extend/engine/GateRestTemplate.java         |   2 +-
 .../it/extend/engine/ITSCBAsyncRestTemplate.java   |   4 +-
 .../it/extend/engine/ITSCBRestTemplate.java        |   2 +-
 .../servicecomb/it/edge/PreLoadBootListener.java   |   2 +-
 .../async/CseAsyncClientHttpRequestTest.java       |   7 +-
 .../servicecomb/serviceregistry/RegistryUtils.java | 229 +++++++++-
 .../serviceregistry/ServiceRegistry.java           |  35 +-
 .../cache/MicroserviceInstanceCache.java           |   8 +-
 .../serviceregistry/client/IpPortManager.java      |   8 +-
 .../client/LocalServiceRegistryClientImpl.java     |  30 +-
 .../client/ServiceRegistryClient.java              |  23 +-
 .../client/http/AbstractClientPool.java            |  40 +-
 .../serviceregistry/client/http/ClientPool.java    |   6 +-
 .../client/http/HttpClientPool.java                |  36 +-
 .../http/{RestUtils.java => RestClientUtil.java}   |  57 +--
 .../serviceregistry/client/http/RestUtils.java     |   5 +
 .../client/http/ServiceRegistryClientImpl.java     |  94 ++--
 .../client/http/WebsocketClientPool.java           |  25 +-
 .../client/http/WebsocketClientUtil.java           | 126 ++++++
 .../client/http/WebsocketUtils.java                |   4 +-
 .../config/ServiceRegistryConfig.java              | 473 +++++++++++++--------
 ...nfig.java => ServiceRegistryConfigBuilder.java} | 194 ++++-----
 .../serviceregistry/consumer/AppManager.java       |  14 +-
 .../consumer/MicroserviceVersion.java              |   6 +-
 .../consumer/MicroserviceVersions.java             |   7 +-
 .../consumer/StaticMicroserviceVersions.java       |   5 +-
 .../diagnosis/instance/InstanceCacheCheckTask.java |   3 +-
 .../serviceregistry/discovery/DiscoveryTree.java   |   1 -
 .../registry/AbstractServiceRegistry.java          | 132 +++---
 .../registry/RemoteServiceRegistry.java            |  20 +-
 .../registry/ServiceRegistryFactory.java           |  28 +-
 .../registry/cache/AggregateMicroserviceCache.java | 139 ++++++
 .../cache/AggregateServiceRegistryCache.java       |  99 +++++
 .../registry/cache/MicroserviceCache.java          |  68 +++
 .../registry/cache/MicroserviceCacheKey.java       | 122 ++++++
 .../cache/MicroserviceCacheRefreshedEvent.java     |  65 ++-
 .../cache/RefreshableMicroserviceCache.java        | 248 +++++++++++
 .../cache/RefreshableServiceRegistryCache.java     | 175 ++++++++
 .../registry/cache/ServiceRegistryCache.java       |  63 ++-
 .../serviceregistry/swagger/SwaggerLoader.java     |  17 +-
 .../serviceregistry/MockMicroserviceVersions.java  |  17 +-
 .../serviceregistry/RegistryUtilsTest.java         |  77 ++++
 .../serviceregistry/ServiceRegistryTest.java       |  68 +++
 .../servicecomb/serviceregistry/TestConsumers.java |  21 +-
 .../servicecomb/serviceregistry/TestRegistry.java  |  10 +-
 .../serviceregistry/TestRegistryBase.java          |  30 +-
 .../cache/TestMicroserviceInstanceCache.java       |  35 +-
 .../client/LocalServiceRegistryClientImplTest.java |  66 +++
 .../serviceregistry/client/TestIpPortManager.java  |   7 +-
 .../serviceregistry/client/http/RestUtilsTest.java |   1 +
 .../client/http/TestClientHttp.java                |  78 ++--
 .../client/http/TestHttpClientPool.java            |  28 +-
 .../client/http/TestServiceRegistryClientImpl.java | 162 ++++---
 .../client/http/TestWebsocketClientPool.java       |  15 +-
 .../config/TestServiceRegistryConfig.java          |  12 +-
 .../instance/TestInstanceCacheChecker.java         |  20 +-
 .../discovery/TestDiscoveryTree.java               |  17 +-
 .../registry/EmptyMockServiceRegistry.java         | 139 ++++++
 .../registry/TestRemoteServiceRegistry.java        |  10 +-
 .../registry/TestServiceRegistryFactory.java       |   8 +-
 .../cache/AggregateMicroserviceCacheTest.java      | 159 +++++++
 .../cache/AggregateServiceRegistryCacheTest.java   | 212 +++++++++
 .../registry/cache/MicroserviceCacheKeyTest.java   |  88 ++++
 .../registry/cache/MockedMicroserviceCache.java}   |  48 +--
 .../cache/RefreshableMicroserviceCacheTest.java    | 367 ++++++++++++++++
 .../cache/RefreshableServiceRegistryCacheTest.java | 205 +++++++++
 .../serviceregistry/swagger/TestSwaggerLoader.java |  35 +-
 .../springboot/common/AbstractDiscoveryClient.java |  26 +-
 81 files changed, 3781 insertions(+), 943 deletions(-)
 copy service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/{RestUtils.java => RestClientUtil.java} (79%)
 create mode 100644 service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientUtil.java
 copy service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/{ServiceRegistryConfig.java => ServiceRegistryConfigBuilder.java} (61%)
 create mode 100644 service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateMicroserviceCache.java
 create mode 100644 service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateServiceRegistryCache.java
 create mode 100644 service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCache.java
 create mode 100644 service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheKey.java
 copy clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroservicesResponse.java => service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheRefreshedEvent.java (67%)
 mode change 100755 => 100644
 create mode 100644 service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableMicroserviceCache.java
 create mode 100644 service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableServiceRegistryCache.java
 copy clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceInstancesResponse.java => service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/ServiceRegistryCache.java (66%)
 mode change 100755 => 100644
 create mode 100644 service-registry/src/test/java/org/apache/servicecomb/serviceregistry/RegistryUtilsTest.java
 create mode 100644 service-registry/src/test/java/org/apache/servicecomb/serviceregistry/ServiceRegistryTest.java
 create mode 100644 service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/EmptyMockServiceRegistry.java
 create mode 100644 service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateMicroserviceCacheTest.java
 create mode 100644 service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateServiceRegistryCacheTest.java
 create mode 100644 service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheKeyTest.java
 copy service-registry/src/{main/java/org/apache/servicecomb/serviceregistry/client/Endpoints.java => test/java/org/apache/servicecomb/serviceregistry/registry/cache/MockedMicroserviceCache.java} (56%)
 create mode 100644 service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableMicroserviceCacheTest.java
 create mode 100644 service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableServiceRegistryCacheTest.java


[servicecomb-java-chassis] 09/19: [SCB-1691] add ServiceRegistryCache

Posted by ya...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

yaohaishi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit e5d89b5e64bfe6f85199efcb3f7a3d452e50c14e
Author: yhs0092 <yh...@163.com>
AuthorDate: Sat Jan 18 15:17:42 2020 +0800

    [SCB-1691] add ServiceRegistryCache
---
 .../serviceregistry/ServiceRegistry.java           |   4 +
 .../registry/AbstractServiceRegistry.java          |   8 +
 .../registry/cache/AggregateMicroserviceCache.java | 139 ++++++++
 .../cache/AggregateServiceRegistryCache.java       |  99 ++++++
 .../registry/cache/MicroserviceCache.java          |  68 ++++
 .../registry/cache/MicroserviceCacheKey.java       | 122 +++++++
 .../cache/MicroserviceCacheRefreshedEvent.java     |  32 ++
 .../cache/RefreshableMicroserviceCache.java        | 248 ++++++++++++++
 .../cache/RefreshableServiceRegistryCache.java     | 175 ++++++++++
 .../registry/cache/ServiceRegistryCache.java       |  30 ++
 .../registry/EmptyMockServiceRegistry.java         | 139 ++++++++
 .../cache/AggregateMicroserviceCacheTest.java      | 159 +++++++++
 .../cache/AggregateServiceRegistryCacheTest.java   | 212 ++++++++++++
 .../registry/cache/MicroserviceCacheKeyTest.java   |  88 +++++
 .../registry/cache/MockedMicroserviceCache.java    |  49 +++
 .../cache/RefreshableMicroserviceCacheTest.java    | 367 +++++++++++++++++++++
 .../cache/RefreshableServiceRegistryCacheTest.java | 205 ++++++++++++
 17 files changed, 2144 insertions(+)

diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/ServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/ServiceRegistry.java
index 0e6e1a2..2de3e83 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/ServiceRegistry.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/ServiceRegistry.java
@@ -25,6 +25,8 @@ import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
 import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient;
 import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances;
+import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache;
+import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCacheKey;
 
 import com.google.common.eventbus.EventBus;
 
@@ -72,6 +74,8 @@ public interface ServiceRegistry {
   MicroserviceInstances findServiceInstances(String appId, String microserviceName,
       String microserviceVersionRule, String revision);
 
+  MicroserviceCache findMicroserviceCache(MicroserviceCacheKey microserviceCacheKey);
+
   boolean updateMicroserviceProperties(Map<String, String> properties);
 
   /**
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java
index baf25dc..a37fdbc 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java
@@ -46,6 +46,8 @@ import org.apache.servicecomb.serviceregistry.consumer.MicroserviceManager;
 import org.apache.servicecomb.serviceregistry.consumer.StaticMicroserviceVersions;
 import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition;
 import org.apache.servicecomb.serviceregistry.definition.MicroserviceNameParser;
+import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache;
+import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCacheKey;
 import org.apache.servicecomb.serviceregistry.task.MicroserviceServiceCenterTask;
 import org.apache.servicecomb.serviceregistry.task.ServiceCenterTask;
 import org.apache.servicecomb.serviceregistry.task.event.RecoveryEvent;
@@ -246,6 +248,12 @@ public abstract class AbstractServiceRegistry implements ServiceRegistry {
   }
 
   @Override
+  public MicroserviceCache findMicroserviceCache(MicroserviceCacheKey microserviceCacheKey) {
+    // TODO find MicroserviceCache from ServiceRegistryCache
+    return null;
+  }
+
+  @Override
   public boolean updateMicroserviceProperties(Map<String, String> properties) {
     boolean success = srClient.updateMicroserviceProperties(microservice.getServiceId(),
         properties);
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateMicroserviceCache.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateMicroserviceCache.java
new file mode 100644
index 0000000..a0082f7
--- /dev/null
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateMicroserviceCache.java
@@ -0,0 +1,139 @@
+/*
+ * 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.serviceregistry.registry.cache;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.servicecomb.serviceregistry.ServiceRegistry;
+import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+
+public class AggregateMicroserviceCache implements MicroserviceCache {
+  private MicroserviceCacheKey key;
+
+  Map<String, MicroserviceCache> caches;
+
+  AtomicLong revisionCounter = new AtomicLong();
+
+  private String revisionId = revisionCounter.toString();
+
+  private MicroserviceCacheStatus status = MicroserviceCacheStatus.INIT;
+
+  private List<MicroserviceInstance> instances = new ArrayList<>();
+
+  Collection<ServiceRegistry> serviceRegistries;
+
+  private final Object refreshLock = new Object();
+
+  public AggregateMicroserviceCache(MicroserviceCacheKey key, Collection<ServiceRegistry> serviceRegistries) {
+    this.key = key;
+    this.serviceRegistries = serviceRegistries;
+
+    refresh();
+  }
+
+  @Override
+  public void refresh() {
+    refreshInnerState(false);
+  }
+
+  private void refreshInnerState(boolean b) {
+    synchronized (refreshLock) {
+      fillInMicroserviceCaches(b);
+      fillInInstanceList();
+      updateRevisionId();
+      refreshStatus();
+    }
+  }
+
+  @Override
+  public void forceRefresh() {
+    refreshInnerState(true);
+  }
+
+  private void fillInMicroserviceCaches(boolean isForce) {
+    HashMap<String, MicroserviceCache> cacheMap = new LinkedHashMap<>();
+    for (ServiceRegistry serviceRegistry : serviceRegistries) {
+      MicroserviceCache microserviceCache = serviceRegistry.findMicroserviceCache(key);
+      if (!isValidMicroserviceCache(microserviceCache)) {
+        continue;
+      }
+      if (isForce) {
+        microserviceCache.forceRefresh();
+      }
+      cacheMap.put(serviceRegistry.getName(), microserviceCache);
+    }
+    caches = cacheMap;
+  }
+
+  private void fillInInstanceList() {
+    ArrayList<MicroserviceInstance> instances = new ArrayList<>();
+    for (Entry<String, MicroserviceCache> stringMicroserviceCacheEntry : caches.entrySet()) {
+      instances.addAll(stringMicroserviceCacheEntry.getValue().getInstances());
+    }
+    this.instances = Collections.unmodifiableList(instances);
+  }
+
+  private void updateRevisionId() {
+    revisionCounter.incrementAndGet();
+    revisionId = revisionCounter.toString();
+  }
+
+  private void refreshStatus() {
+    if (caches.size() == 0) {
+      status = MicroserviceCacheStatus.SERVICE_NOT_FOUND;
+    } else {
+      status = MicroserviceCacheStatus.REFRESHED;
+    }
+  }
+
+  private boolean isValidMicroserviceCache(MicroserviceCache microserviceCache) {
+    return !(
+        Objects.isNull(microserviceCache)
+            || MicroserviceCacheStatus.SERVICE_NOT_FOUND.equals(microserviceCache.getStatus())
+    );
+  }
+
+  @Override
+  public MicroserviceCacheKey getKey() {
+    return key;
+  }
+
+  @Override
+  public List<MicroserviceInstance> getInstances() {
+    return instances;
+  }
+
+  @Override
+  public String getRevisionId() {
+    return revisionId;
+  }
+
+  @Override
+  public MicroserviceCacheStatus getStatus() {
+    return status;
+  }
+}
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateServiceRegistryCache.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateServiceRegistryCache.java
new file mode 100644
index 0000000..687cccc
--- /dev/null
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateServiceRegistryCache.java
@@ -0,0 +1,99 @@
+/*
+ * 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.serviceregistry.registry.cache;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx;
+import org.apache.servicecomb.serviceregistry.ServiceRegistry;
+import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache.MicroserviceCacheStatus;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.eventbus.Subscribe;
+
+public class AggregateServiceRegistryCache implements ServiceRegistryCache {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(AggregateServiceRegistryCache.class);
+
+  Collection<ServiceRegistry> serviceRegistries;
+
+  final Map<MicroserviceCacheKey, AggregateMicroserviceCache> microserviceCache = new ConcurrentHashMapEx<>();
+
+  private Consumer<List<MicroserviceCache>> cacheRefreshedWatcher;
+
+  public AggregateServiceRegistryCache(Collection<ServiceRegistry> serviceRegistries) {
+    this.serviceRegistries = serviceRegistries;
+  }
+
+  @Override
+  public MicroserviceCache findServiceCache(MicroserviceCacheKey microserviceCacheKey) {
+    AggregateMicroserviceCache microserviceCache = this.microserviceCache.computeIfAbsent(microserviceCacheKey,
+        key -> new AggregateMicroserviceCache(key, serviceRegistries));
+    removeMicroserviceCacheIfNotExist(microserviceCache);
+    return microserviceCache;
+  }
+
+  @Override
+  public ServiceRegistryCache setCacheRefreshedWatcher(Consumer<List<MicroserviceCache>> cacheRefreshedWatcher) {
+    this.cacheRefreshedWatcher = cacheRefreshedWatcher;
+    return this;
+  }
+
+  @Subscribe
+  public void onMicroserviceCacheRefreshed(MicroserviceCacheRefreshedEvent event) {
+    List<MicroserviceCache> microserviceCaches = event.getMicroserviceCaches();
+    if (null == microserviceCaches || microserviceCaches.isEmpty()) {
+      return;
+    }
+
+    List<MicroserviceCache> refreshedAggregateMicroserviceCaches = microserviceCaches.stream()
+        .map(cache -> this.microserviceCache.get(cache.getKey()))
+        .filter(Objects::nonNull)
+        .peek(AggregateMicroserviceCache::refresh)
+        .peek(this::removeMicroserviceCacheIfNotExist)
+        .collect(Collectors.toList());
+
+    LOGGER.info("[{}] caches get refreshed", refreshedAggregateMicroserviceCaches.size());
+    refreshedAggregateMicroserviceCaches.forEach(cache -> {
+      LOGGER.info("[{}]: status={}, revisionId={}", cache.getKey(), cache.getStatus(), cache.getRevisionId());
+    });
+
+    if (null != cacheRefreshedWatcher) {
+      cacheRefreshedWatcher.accept(refreshedAggregateMicroserviceCaches);
+    }
+  }
+
+  private void removeMicroserviceCacheIfNotExist(MicroserviceCache cache) {
+    if (MicroserviceCacheStatus.SERVICE_NOT_FOUND.equals(cache.getStatus())) {
+      microserviceCache.remove(cache.getKey());
+      LOGGER.info("microserviceCache[{}] got removed", cache.getKey());
+    }
+  }
+
+  @Override
+  public Map<MicroserviceCacheKey, MicroserviceCache> getMicroserviceCaches() {
+    return Collections.unmodifiableMap(microserviceCache);
+  }
+}
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCache.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCache.java
new file mode 100644
index 0000000..d6a49c2
--- /dev/null
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCache.java
@@ -0,0 +1,68 @@
+/*
+ * 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.serviceregistry.registry.cache;
+
+import java.util.List;
+
+import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+
+public interface MicroserviceCache {
+  MicroserviceCacheKey getKey();
+
+  List<MicroserviceInstance> getInstances();
+
+  String getRevisionId();
+
+  MicroserviceCacheStatus getStatus();
+
+  void refresh();
+
+  void forceRefresh();
+
+  enum MicroserviceCacheStatus {
+    /**
+     * init status, not pull instances from sc yet
+     */
+    INIT,
+    /**
+     * unknown error
+     */
+    UNKNOWN_ERROR,
+    /**
+     * error occurs while getting access to service center
+     */
+    CLIENT_ERROR,
+    /**
+     * success to query the service center, but no target microservice found
+     */
+    SERVICE_NOT_FOUND,
+    /**
+     * success to query the service center, but the target microservice instance list is not changed
+     */
+    NO_CHANGE,
+    /**
+     * success to query the service center, and the target microservice instance list is changed.
+     * the cached instance list gets refreshed successfully.
+     */
+    REFRESHED,
+    /**
+     * unknown error occurs while setting the pulled instances into this cache
+     */
+    SETTING_CACHE_ERROR
+  }
+}
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheKey.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheKey.java
new file mode 100644
index 0000000..103df5a
--- /dev/null
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheKey.java
@@ -0,0 +1,122 @@
+/*
+ * 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.serviceregistry.registry.cache;
+
+import java.util.Objects;
+
+import org.apache.servicecomb.serviceregistry.definition.DefinitionConst;
+import org.apache.servicecomb.serviceregistry.definition.MicroserviceNameParser;
+
+public class MicroserviceCacheKey {
+  private String env;
+
+  private String appId;
+
+  private String serviceName;
+
+  private static final String VERSION_RULE = DefinitionConst.VERSION_RULE_ALL;
+
+  public static MicroserviceCacheKeyBuilder builder() {
+    return new MicroserviceCacheKeyBuilder();
+  }
+
+  MicroserviceCacheKey() {
+  }
+
+  public void validate() {
+    Objects.requireNonNull(this.env, "microserviceCacheKey.env is null");
+    Objects.requireNonNull(this.appId, "microserviceCacheKey.appId is null");
+    Objects.requireNonNull(this.serviceName, "microserviceCacheKey.serviceName is null");
+  }
+
+  public String getEnv() {
+    return env;
+  }
+
+  public String getAppId() {
+    return appId;
+  }
+
+  public String getServiceName() {
+    return serviceName;
+  }
+
+  public String getVersionRule() {
+    return VERSION_RULE;
+  }
+
+  public String plainKey() {
+    return serviceName + "@" + appId + "@" + env;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    MicroserviceCacheKey that = (MicroserviceCacheKey) o;
+    return Objects.equals(env, that.env) &&
+        Objects.equals(appId, that.appId) &&
+        Objects.equals(serviceName, that.serviceName);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(env, appId, serviceName);
+  }
+
+  @Override
+  public String toString() {
+    return plainKey();
+  }
+
+  public static class MicroserviceCacheKeyBuilder {
+    private MicroserviceCacheKey microserviceCacheKey;
+
+    public MicroserviceCacheKey build() {
+      microserviceCacheKey.validate();
+      MicroserviceNameParser microserviceNameParser =
+          new MicroserviceNameParser(microserviceCacheKey.appId, microserviceCacheKey.serviceName);
+      microserviceCacheKey.appId = microserviceNameParser.getAppId();
+      microserviceCacheKey.serviceName = microserviceNameParser.getShortName();
+      return microserviceCacheKey;
+    }
+
+    public MicroserviceCacheKeyBuilder env(String env) {
+      microserviceCacheKey.env = env;
+      return this;
+    }
+
+    public MicroserviceCacheKeyBuilder appId(String appId) {
+      microserviceCacheKey.appId = appId;
+      return this;
+    }
+
+    public MicroserviceCacheKeyBuilder serviceName(String serviceName) {
+      microserviceCacheKey.serviceName = serviceName;
+      return this;
+    }
+
+    MicroserviceCacheKeyBuilder() {
+      microserviceCacheKey = new MicroserviceCacheKey();
+    }
+  }
+}
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheRefreshedEvent.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheRefreshedEvent.java
new file mode 100644
index 0000000..2bfea47
--- /dev/null
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheRefreshedEvent.java
@@ -0,0 +1,32 @@
+/*
+ * 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.serviceregistry.registry.cache;
+
+import java.util.List;
+
+public class MicroserviceCacheRefreshedEvent {
+  private final List<MicroserviceCache> microserviceCaches;
+
+  public MicroserviceCacheRefreshedEvent(List<MicroserviceCache> microserviceCaches) {
+    this.microserviceCaches = microserviceCaches;
+  }
+
+  public List<MicroserviceCache> getMicroserviceCaches() {
+    return microserviceCaches;
+  }
+}
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableMicroserviceCache.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableMicroserviceCache.java
new file mode 100644
index 0000000..9a74cf0
--- /dev/null
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableMicroserviceCache.java
@@ -0,0 +1,248 @@
+/*
+ * 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.serviceregistry.registry.cache;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
+import org.apache.servicecomb.serviceregistry.api.Const;
+import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
+import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent;
+import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient;
+import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances;
+import org.apache.servicecomb.serviceregistry.consumer.MicroserviceInstancePing;
+import org.apache.servicecomb.serviceregistry.task.event.SafeModeChangeEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RefreshableMicroserviceCache implements MicroserviceCache {
+  private static final Logger LOGGER = LoggerFactory.getLogger(RefreshableMicroserviceCache.class);
+
+  MicroserviceCacheKey key;
+
+  List<MicroserviceInstance> instances = Collections.unmodifiableList(new ArrayList<>());
+
+  Microservice consumerService;
+
+  String revisionId;
+
+  ServiceRegistryClient srClient;
+
+  boolean safeMode;
+
+  MicroserviceCacheStatus status = MicroserviceCacheStatus.INIT;
+
+  private final Object SET_OPERATION_LOCK = new Object();
+
+  boolean emptyInstanceProtectionEnabled;
+
+  MicroserviceInstancePing instancePing = SPIServiceUtils.getPriorityHighestService(MicroserviceInstancePing.class);
+
+  RefreshableMicroserviceCache(Microservice consumerService, MicroserviceCacheKey key, ServiceRegistryClient srClient,
+      boolean emptyInstanceProtectionEnabled) {
+    this.key = key;
+    this.consumerService = consumerService;
+    this.srClient = srClient;
+    this.emptyInstanceProtectionEnabled = emptyInstanceProtectionEnabled;
+  }
+
+  @Override
+  public void refresh() {
+    safePullInstance(revisionId);
+  }
+
+  @Override
+  public void forceRefresh() {
+    safePullInstance(null);
+  }
+
+  void safePullInstance(String revisionId) {
+    try {
+      pullInstance(revisionId);
+    } catch (Throwable e) {
+      LOGGER.error("unknown error occurs while pulling instances", e);
+      setStatus(MicroserviceCacheStatus.UNKNOWN_ERROR);
+    }
+  }
+
+  void pullInstance(String revisionId) {
+    MicroserviceInstances serviceInstances = pullInstanceFromServiceCenter(revisionId);
+
+    if (serviceInstances == null) {
+      LOGGER.error("Can not find any instances from service center due to previous errors. service={}/{}/{}",
+          key.getAppId(),
+          key.getServiceName(),
+          key.getVersionRule());
+      setStatus(MicroserviceCacheStatus.CLIENT_ERROR);
+      return;
+    }
+
+    if (serviceInstances.isMicroserviceNotExist()) {
+      setStatus(MicroserviceCacheStatus.SERVICE_NOT_FOUND);
+      return;
+    }
+
+    if (!serviceInstances.isNeedRefresh()) {
+      LOGGER.debug("instances revision is not changed, service={}/{}/{}", key.getAppId(), key.getServiceName(),
+          key.getVersionRule());
+      setStatus(MicroserviceCacheStatus.NO_CHANGE);
+      return;
+    }
+
+    List<MicroserviceInstance> instances = serviceInstances.getInstancesResponse().getInstances();
+    LOGGER.info("find instances[{}] from service center success. service={}/{}/{}, old revision={}, new revision={}",
+        instances.size(),
+        key.getAppId(),
+        key.getServiceName(),
+        key.getVersionRule(),
+        this.revisionId,
+        serviceInstances.getRevision());
+    for (MicroserviceInstance instance : instances) {
+      LOGGER.info("service id={}, instance id={}, endpoints={}",
+          instance.getServiceId(),
+          instance.getInstanceId(),
+          instance.getEndpoints());
+    }
+    safeSetInstances(instances, serviceInstances.getRevision());
+  }
+
+  MicroserviceInstances pullInstanceFromServiceCenter(String revisionId) {
+    return srClient.findServiceInstances(consumerService.getServiceId(),
+        key.getAppId(), key.getServiceName(), key.getVersionRule(), revisionId);
+  }
+
+  private void safeSetInstances(List<MicroserviceInstance> pulledInstances, String rev) {
+    try {
+      synchronized (SET_OPERATION_LOCK) {
+        setInstances(pulledInstances, rev);
+        setStatus(MicroserviceCacheStatus.REFRESHED);
+      }
+    } catch (Throwable e) {
+      setStatus(MicroserviceCacheStatus.SETTING_CACHE_ERROR);
+      LOGGER.error("Failed to setInstances, appId={}, microserviceName={}.",
+          key.getAppId(),
+          key.getServiceName(),
+          e);
+    }
+  }
+
+  private void setInstances(List<MicroserviceInstance> pulledInstances, String rev) {
+    Set<MicroserviceInstance> mergedInstances = mergeInstances(pulledInstances);
+    LOGGER.debug("actually set instances[{}] for {}", mergedInstances.size(), key.plainKey());
+    for (MicroserviceInstance mergedInstance : mergedInstances) {
+      LOGGER.debug("serviceId={}, instanceId={}, endpoints={}",
+          mergedInstance.getServiceId(),
+          mergedInstance.getInstanceId(),
+          mergedInstance.getEndpoints());
+    }
+    instances = Collections.unmodifiableList(new ArrayList<>(mergedInstances));
+    revisionId = rev;
+  }
+
+  protected Set<MicroserviceInstance> mergeInstances(List<MicroserviceInstance> pulledInstances) {
+    Set<MicroserviceInstance> mergedInstances = new LinkedHashSet<>(pulledInstances);
+
+    if (safeMode) {
+      // in safe mode, instances will never be deleted
+      mergedInstances.addAll(instances);
+      return mergedInstances;
+    }
+
+    if (!inEmptyPulledInstancesProtectionSituation(pulledInstances)) {
+      return mergedInstances;
+    }
+
+    if (null == instancePing) {
+      LOGGER.info("no MicroserviceInstancePing implementation loaded, abandon the old instance list");
+      return mergedInstances;
+    }
+
+    instances.forEach(instance -> {
+      if (!mergedInstances.contains(instance)) {
+        if (instancePing.ping(instance)) {
+          mergedInstances.add(instance);
+        }
+      }
+    });
+    return mergedInstances;
+  }
+
+  private boolean inEmptyPulledInstancesProtectionSituation(List<MicroserviceInstance> pulledInstances) {
+    return pulledInstances.isEmpty()
+        && instances != null
+        && !instances.isEmpty()
+        && isEmptyInstanceProtectionEnabled();
+  }
+
+  @Override
+  public MicroserviceCacheKey getKey() {
+    return key;
+  }
+
+  @Override
+  public List<MicroserviceInstance> getInstances() {
+    return instances;
+  }
+
+  @Override
+  public String getRevisionId() {
+    return revisionId;
+  }
+
+  @Override
+  public MicroserviceCacheStatus getStatus() {
+    return status;
+  }
+
+  void setStatus(MicroserviceCacheStatus status) {
+    this.status = status;
+  }
+
+  boolean isEmptyInstanceProtectionEnabled() {
+    return emptyInstanceProtectionEnabled;
+  }
+
+  void setEmptyInstanceProtectionEnabled(boolean emptyInstanceProtectionEnabled) {
+    this.emptyInstanceProtectionEnabled = emptyInstanceProtectionEnabled;
+  }
+
+  void onMicroserviceInstanceChanged(MicroserviceInstanceChangedEvent event) {
+    if (!microserviceMatched(event)) {
+      return;
+    }
+    refresh();
+  }
+
+  void onSafeModeChanged(SafeModeChangeEvent modeChangeEvent) {
+    this.safeMode = modeChangeEvent.getCurrentMode();
+  }
+
+  private boolean microserviceMatched(MicroserviceInstanceChangedEvent event) {
+    return (key.getAppId().equals(event.getKey().getAppId())) // appId matched
+        && ( // microserviceName matched
+        key.getServiceName().equals(event.getKey().getServiceName())
+            || key.getServiceName().equals(
+            event.getKey().getAppId() + Const.APP_SERVICE_SEPARATOR + event.getKey().getServiceName()
+        ));
+  }
+}
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableServiceRegistryCache.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableServiceRegistryCache.java
new file mode 100644
index 0000000..7bd1a1b
--- /dev/null
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableServiceRegistryCache.java
@@ -0,0 +1,175 @@
+/*
+ * 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.serviceregistry.registry.cache;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx;
+import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
+import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent;
+import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient;
+import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache.MicroserviceCacheStatus;
+import org.apache.servicecomb.serviceregistry.task.event.SafeModeChangeEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Cache the pulled microservice instances.
+ */
+public class RefreshableServiceRegistryCache implements ServiceRegistryCache {
+  private static final Logger LOGGER = LoggerFactory.getLogger(RefreshableServiceRegistryCache.class);
+
+  Map<MicroserviceCacheKey, RefreshableMicroserviceCache> microserviceCache = new ConcurrentHashMapEx<>();
+
+  Microservice consumerService;
+
+  ServiceRegistryClient srClient;
+
+  boolean emptyInstanceProtectionEnabled = false;
+
+  Consumer<List<MicroserviceCache>> cacheRefreshedWatcher;
+
+  ReentrantLock refreshLock = new ReentrantLock();
+
+  public RefreshableServiceRegistryCache(Microservice consumerService, ServiceRegistryClient srClient) {
+    this.consumerService = consumerService;
+    this.srClient = srClient;
+  }
+
+  public void refreshCache() {
+    if (!refreshLock.tryLock()) {
+      LOGGER.info("ignore concurrent refresh request");
+      return;
+    }
+
+    try {
+      List<MicroserviceCache> refreshedCaches = refreshInnerState(false);
+      notifyWatcher(refreshedCaches);
+    } catch (Exception e) {
+      LOGGER.error("failed to refresh caches", e);
+    } finally {
+      refreshLock.unlock();
+    }
+  }
+
+  public void forceRefreshCache() {
+    refreshLock.lock();
+    try {
+      List<MicroserviceCache> refreshedCaches = refreshInnerState(true);
+      notifyWatcher(refreshedCaches);
+    } catch (Exception e) {
+      LOGGER.error("failed to refresh caches", e);
+    } finally {
+      refreshLock.unlock();
+    }
+  }
+
+  private List<MicroserviceCache> refreshInnerState(boolean isForced) {
+    return microserviceCache.values().stream()
+        .peek(cache -> {
+          if (isForced) {
+            cache.forceRefresh();
+          } else {
+            cache.refresh();
+          }
+        })
+        .filter(this::isRefreshedMicroserviceCache)
+        .peek(this::removeCacheIfServiceNotFound)
+        .collect(Collectors.toList());
+  }
+
+  private boolean isRefreshedMicroserviceCache(MicroserviceCache microserviceCache) {
+    return MicroserviceCacheStatus.REFRESHED.equals(microserviceCache.getStatus())
+        || MicroserviceCacheStatus.SERVICE_NOT_FOUND.equals(microserviceCache.getStatus());
+  }
+
+  private void notifyWatcher(List<MicroserviceCache> refreshedCaches) {
+    if (refreshedCaches.isEmpty() || null == cacheRefreshedWatcher) {
+      return;
+    }
+    cacheRefreshedWatcher.accept(refreshedCaches);
+  }
+
+  @Override
+  public MicroserviceCache findServiceCache(MicroserviceCacheKey microserviceCacheKey) {
+    microserviceCacheKey.validate();
+    RefreshableMicroserviceCache targetCache = microserviceCache
+        .computeIfAbsent(microserviceCacheKey, pk -> {
+          RefreshableMicroserviceCache microserviceCache = createMicroserviceCache(microserviceCacheKey);
+          microserviceCache.refresh();
+          return microserviceCache;
+        });
+    removeCacheIfServiceNotFound(targetCache);
+    return targetCache;
+  }
+
+  private void removeCacheIfServiceNotFound(MicroserviceCache targetCache) {
+    if (MicroserviceCacheStatus.SERVICE_NOT_FOUND.equals(targetCache.getStatus())) {
+      microserviceCache.remove(targetCache.getKey());
+      LOGGER.info("microserviceCache[{}] got removed", targetCache.getKey());
+    }
+  }
+
+  RefreshableMicroserviceCache createMicroserviceCache(MicroserviceCacheKey microserviceCacheKey) {
+    return new RefreshableMicroserviceCache(
+        consumerService,
+        microserviceCacheKey,
+        srClient,
+        emptyInstanceProtectionEnabled);
+  }
+
+  public RefreshableServiceRegistryCache setEmptyInstanceProtectionEnabled(boolean emptyInstanceProtectionEnabled) {
+    this.emptyInstanceProtectionEnabled = emptyInstanceProtectionEnabled;
+    return this;
+  }
+
+  @Override
+  public ServiceRegistryCache setCacheRefreshedWatcher(
+      Consumer<List<MicroserviceCache>> cacheRefreshedWatcher) {
+    this.cacheRefreshedWatcher = cacheRefreshedWatcher;
+    return this;
+  }
+
+  public void onMicroserviceInstanceChanged(MicroserviceInstanceChangedEvent event) {
+    List<MicroserviceCache> refreshedCaches =
+        microserviceCache.entrySet().stream()
+            .peek(cacheEntry -> cacheEntry.getValue().onMicroserviceInstanceChanged(event))
+            .filter(cacheEntry -> isRefreshedMicroserviceCache(cacheEntry.getValue()))
+            .map(Entry::getValue)
+            .collect(Collectors.toList());
+
+    notifyWatcher(refreshedCaches);
+  }
+
+  public void onSafeModeChanged(SafeModeChangeEvent modeChangeEvent) {
+    for (Entry<MicroserviceCacheKey, RefreshableMicroserviceCache> cacheEntry : microserviceCache.entrySet()) {
+      cacheEntry.getValue().onSafeModeChanged(modeChangeEvent);
+    }
+  }
+
+  @Override
+  public Map<MicroserviceCacheKey, MicroserviceCache> getMicroserviceCaches() {
+    return Collections.unmodifiableMap(microserviceCache);
+  }
+}
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/ServiceRegistryCache.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/ServiceRegistryCache.java
new file mode 100644
index 0000000..fdc27fe
--- /dev/null
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/cache/ServiceRegistryCache.java
@@ -0,0 +1,30 @@
+/*
+ * 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.serviceregistry.registry.cache;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+
+public interface ServiceRegistryCache {
+  MicroserviceCache findServiceCache(MicroserviceCacheKey microserviceCacheKey);
+
+  ServiceRegistryCache setCacheRefreshedWatcher(Consumer<List<MicroserviceCache>> cacheRefreshedWatcher);
+
+  Map<MicroserviceCacheKey, MicroserviceCache> getMicroserviceCaches();
+}
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/EmptyMockServiceRegistry.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/EmptyMockServiceRegistry.java
new file mode 100644
index 0000000..d14532e
--- /dev/null
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/EmptyMockServiceRegistry.java
@@ -0,0 +1,139 @@
+/*
+ * 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.serviceregistry.registry;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.servicecomb.serviceregistry.Features;
+import org.apache.servicecomb.serviceregistry.ServiceRegistry;
+import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
+import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient;
+import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances;
+import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache;
+import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCacheKey;
+
+import com.google.common.eventbus.EventBus;
+
+public class EmptyMockServiceRegistry implements ServiceRegistry {
+  @Override
+  public String getName() {
+    return null;
+  }
+
+  @Override
+  public void init() {
+
+  }
+
+  @Override
+  public void run() {
+
+  }
+
+  @Override
+  public void destroy() {
+
+  }
+
+  @Override
+  public EventBus getEventBus() {
+    return null;
+  }
+
+  @Override
+  public Set<String> getCombinedMicroserviceNames() {
+    return null;
+  }
+
+  @Override
+  public String getAppId() {
+    return null;
+  }
+
+  @Override
+  public Microservice getMicroservice() {
+    return null;
+  }
+
+  @Override
+  public MicroserviceInstance getMicroserviceInstance() {
+    return null;
+  }
+
+  @Override
+  public ServiceRegistryClient getServiceRegistryClient() {
+    return null;
+  }
+
+  @Override
+  public List<MicroserviceInstance> findServiceInstance(String appId, String microserviceName,
+      String microserviceVersionRule) {
+    return null;
+  }
+
+  @Override
+  public MicroserviceInstances findServiceInstances(String appId, String microserviceName,
+      String microserviceVersionRule, String revision) {
+    return null;
+  }
+
+  @Override
+  public MicroserviceCache findMicroserviceCache(MicroserviceCacheKey microserviceCacheKey) {
+    return null;
+  }
+
+  @Override
+  public boolean updateMicroserviceProperties(Map<String, String> properties) {
+    return false;
+  }
+
+  @Override
+  public boolean updateInstanceProperties(Map<String, String> instanceProperties) {
+    return false;
+  }
+
+  @Override
+  public Microservice getRemoteMicroservice(String microserviceId) {
+    return null;
+  }
+
+  @Override
+  public Microservice getAggregatedRemoteMicroservice(String microserviceId) {
+    return null;
+  }
+
+  @Override
+  public Features getFeatures() {
+    return null;
+  }
+
+  @Override
+  public void registerMicroserviceMapping(String microserviceName, String version, List<MicroserviceInstance> instances,
+      Class<?> schemaIntfCls) {
+
+  }
+
+  @Override
+  public void registerMicroserviceMappingByEndpoints(String microserviceName, String version, List<String> endpoints,
+      Class<?> schemaIntfCls) {
+
+  }
+}
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateMicroserviceCacheTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateMicroserviceCacheTest.java
new file mode 100644
index 0000000..9de57c8
--- /dev/null
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateMicroserviceCacheTest.java
@@ -0,0 +1,159 @@
+/*
+ * 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.serviceregistry.registry.cache;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.servicecomb.serviceregistry.ServiceRegistry;
+import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+import org.apache.servicecomb.serviceregistry.registry.EmptyMockServiceRegistry;
+import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache.MicroserviceCacheStatus;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class AggregateMicroserviceCacheTest {
+
+  @Test
+  public void refresh() {
+    MicroserviceCacheKey microserviceCacheKey =
+        MicroserviceCacheKey.builder().serviceName("svc").appId("app").env("production").build();
+
+    MockMicroserviceCache mockMicroserviceCache0 = new MockMicroserviceCache(microserviceCacheKey,
+        MicroserviceCacheStatus.NO_CHANGE);
+    MockMicroserviceCache mockMicroserviceCache2 = new MockMicroserviceCache(microserviceCacheKey,
+        MicroserviceCacheStatus.REFRESHED);
+    mockMicroserviceCache2.instances = Arrays.asList(new MicroserviceInstance(), new MicroserviceInstance());
+    MockMicroserviceCache mockMicroserviceCache3 = new MockMicroserviceCache(microserviceCacheKey,
+        MicroserviceCacheStatus.SERVICE_NOT_FOUND);
+
+    MockServiceRegistry mockServiceRegistry0 = new MockServiceRegistry().setName("s0")
+        .addCache(mockMicroserviceCache0)
+        .addCache(new MockMicroserviceCache(
+            MicroserviceCacheKey.builder().serviceName("svc2").appId("app").env("production").build(),
+            MicroserviceCacheStatus.REFRESHED));
+    MockServiceRegistry mockServiceRegistry1 = new MockServiceRegistry().setName("s1");
+    MockServiceRegistry mockServiceRegistry2 = new MockServiceRegistry().setName("s2")
+        .addCache(mockMicroserviceCache2);
+    MockServiceRegistry mockServiceRegistry3 = new MockServiceRegistry().setName("s3")
+        .addCache(mockMicroserviceCache3);
+
+    List<ServiceRegistry> serviceRegistries = Arrays.asList(
+        mockServiceRegistry0,
+        mockServiceRegistry1,
+        mockServiceRegistry2,
+        mockServiceRegistry3
+    );
+
+    AggregateMicroserviceCache compositeMicroserviceCache = new AggregateMicroserviceCache(
+        microserviceCacheKey,
+        serviceRegistries);
+
+    // Test initialization
+    // key
+    Assert.assertSame(microserviceCacheKey, compositeMicroserviceCache.getKey());
+    // status
+    Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, compositeMicroserviceCache.getStatus());
+    // revision
+    Assert.assertEquals("1", compositeMicroserviceCache.getRevisionId());
+    Assert.assertEquals(1L, compositeMicroserviceCache.revisionCounter.get());
+    // MicroserviceCache map
+    Assert.assertEquals(2, compositeMicroserviceCache.caches.size());
+    Assert.assertSame(mockMicroserviceCache0, compositeMicroserviceCache.caches.get("s0"));
+    Assert.assertSame(mockMicroserviceCache2, compositeMicroserviceCache.caches.get("s2"));
+    // ServiceRegistry collection
+    Assert.assertEquals(serviceRegistries.size(), compositeMicroserviceCache.serviceRegistries.size());
+    Iterator<ServiceRegistry> serviceRegistryIterator = compositeMicroserviceCache.serviceRegistries.iterator();
+    Assert.assertSame(serviceRegistries.get(0), serviceRegistryIterator.next());
+    Assert.assertSame(serviceRegistries.get(1), serviceRegistryIterator.next());
+    Assert.assertSame(serviceRegistries.get(2), serviceRegistryIterator.next());
+    Assert.assertSame(serviceRegistries.get(3), serviceRegistryIterator.next());
+    // cached instances
+    Assert.assertEquals(2, compositeMicroserviceCache.getInstances().size());
+    Assert.assertSame(mockMicroserviceCache2.instances.get(0), compositeMicroserviceCache.getInstances().get(0));
+    Assert.assertSame(mockMicroserviceCache2.instances.get(1), compositeMicroserviceCache.getInstances().get(1));
+
+    // Test refresh()
+    mockMicroserviceCache0.instances = Collections.singletonList(new MicroserviceInstance());
+    mockMicroserviceCache2.instances = Collections.singletonList(new MicroserviceInstance());
+    compositeMicroserviceCache.refresh();
+    // status
+    Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, compositeMicroserviceCache.getStatus());
+    // revision
+    Assert.assertEquals("2", compositeMicroserviceCache.getRevisionId());
+    Assert.assertEquals(2L, compositeMicroserviceCache.revisionCounter.get());
+    // cached instances
+    Assert.assertEquals(2, compositeMicroserviceCache.getInstances().size());
+    Assert.assertSame(mockMicroserviceCache0.instances.get(0), compositeMicroserviceCache.getInstances().get(0));
+    Assert.assertSame(mockMicroserviceCache2.instances.get(0), compositeMicroserviceCache.getInstances().get(1));
+
+    // Test refresh()
+    // microservice deleted and registered
+    mockMicroserviceCache0.status = MicroserviceCacheStatus.SERVICE_NOT_FOUND;
+    mockMicroserviceCache3.status = MicroserviceCacheStatus.REFRESHED;
+    compositeMicroserviceCache.refresh();
+    // status
+    Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, compositeMicroserviceCache.getStatus());
+    // revision
+    Assert.assertEquals("3", compositeMicroserviceCache.getRevisionId());
+    Assert.assertEquals(3L, compositeMicroserviceCache.revisionCounter.get());
+    // ServiceRegistries
+    Assert.assertNotNull(compositeMicroserviceCache.caches.get("s2"));
+    Assert.assertNotNull(compositeMicroserviceCache.caches.get("s3"));
+    // cached instances
+    Assert.assertEquals(1, compositeMicroserviceCache.getInstances().size());
+    Assert.assertSame(mockMicroserviceCache2.instances.get(0), compositeMicroserviceCache.getInstances().get(0));
+  }
+
+  public static class MockServiceRegistry extends EmptyMockServiceRegistry {
+    String name;
+
+    Map<MicroserviceCacheKey, MicroserviceCache> cacheMap = new HashMap<>();
+
+    public MockServiceRegistry setName(String name) {
+      this.name = name;
+      return this;
+    }
+
+    public MockServiceRegistry addCache(MicroserviceCache microserviceCache) {
+      cacheMap.put(microserviceCache.getKey(), microserviceCache);
+      return this;
+    }
+
+    @Override
+    public String getName() {
+      return name;
+    }
+
+    @Override
+    public MicroserviceCache findMicroserviceCache(MicroserviceCacheKey microserviceCacheKey) {
+      return cacheMap.get(microserviceCacheKey);
+    }
+  }
+
+  public static class MockMicroserviceCache extends RefreshableMicroserviceCache {
+    public MockMicroserviceCache(MicroserviceCacheKey key, MicroserviceCacheStatus microserviceCacheStatus) {
+      super(null, key, null, false);
+      setStatus(microserviceCacheStatus);
+    }
+  }
+}
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateServiceRegistryCacheTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateServiceRegistryCacheTest.java
new file mode 100644
index 0000000..3ce08f5
--- /dev/null
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/AggregateServiceRegistryCacheTest.java
@@ -0,0 +1,212 @@
+/*
+ * 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.serviceregistry.registry.cache;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.apache.servicecomb.serviceregistry.registry.cache.AggregateMicroserviceCacheTest.MockMicroserviceCache;
+import org.apache.servicecomb.serviceregistry.registry.cache.AggregateMicroserviceCacheTest.MockServiceRegistry;
+import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache.MicroserviceCacheStatus;
+import org.junit.Before;
+import org.junit.Test;
+
+public class AggregateServiceRegistryCacheTest {
+
+  private MicroserviceCacheKey microserviceCacheKey;
+
+  private MockServiceRegistry mockServiceRegistry0;
+
+  private MockServiceRegistry mockServiceRegistry1;
+
+  private MockServiceRegistry mockServiceRegistry2;
+
+  private AggregateServiceRegistryCache aggregateServiceRegistryCache;
+
+  @Before
+  public void before() {
+    microserviceCacheKey = MicroserviceCacheKey.builder()
+        .serviceName("svc").appId("app").env("env").build();
+
+    mockServiceRegistry0 = new MockServiceRegistry()
+        .setName("s0")
+        .addCache(new MockMicroserviceCache(
+            microserviceCacheKey,
+            MicroserviceCacheStatus.NO_CHANGE));
+    mockServiceRegistry1 = new MockServiceRegistry()
+        .setName("s1")
+        .addCache(new MockMicroserviceCache(
+            microserviceCacheKey,
+            MicroserviceCacheStatus.REFRESHED))
+        .addCache(new MockMicroserviceCache(
+            MicroserviceCacheKey.builder().serviceName("svc2").appId("app").env("env").build(),
+            MicroserviceCacheStatus.NO_CHANGE));
+    mockServiceRegistry2 = new MockServiceRegistry()
+        .setName("s2")
+        .addCache(new MockMicroserviceCache(
+            microserviceCacheKey,
+            MicroserviceCacheStatus.SERVICE_NOT_FOUND));
+
+    aggregateServiceRegistryCache = new AggregateServiceRegistryCache(
+        Arrays.asList(mockServiceRegistry0, mockServiceRegistry1, mockServiceRegistry2));
+  }
+
+  @Test
+  public void findServiceCache() {
+    MicroserviceCache serviceCache = aggregateServiceRegistryCache.findServiceCache(
+        MicroserviceCacheKey.builder().serviceName("svc").appId("app").env("env").build()
+    );
+
+    assertTrue(serviceCache instanceof AggregateMicroserviceCache);
+    AggregateMicroserviceCache aggregateMicroserviceCache = (AggregateMicroserviceCache) serviceCache;
+    assertEquals(2, aggregateMicroserviceCache.caches.size());
+    assertSame(mockServiceRegistry0.findMicroserviceCache(microserviceCacheKey),
+        aggregateMicroserviceCache.caches.get(mockServiceRegistry0.getName()));
+    assertSame(mockServiceRegistry1.findMicroserviceCache(microserviceCacheKey),
+        aggregateMicroserviceCache.caches.get(mockServiceRegistry1.getName()));
+    // aggregateMicroserviceCache holds the cache of svc
+    assertEquals(1, aggregateServiceRegistryCache.microserviceCache.size());
+    assertNotNull(aggregateServiceRegistryCache.microserviceCache.get(microserviceCacheKey));
+
+    MicroserviceCache serviceCache2 = aggregateServiceRegistryCache.findServiceCache(
+        MicroserviceCacheKey.builder().serviceName("svc2").appId("app").env("env").build()
+    );
+
+    assertTrue(serviceCache2 instanceof AggregateMicroserviceCache);
+    AggregateMicroserviceCache aggregateMicroserviceCache2 = (AggregateMicroserviceCache) serviceCache2;
+    assertEquals(1, aggregateMicroserviceCache2.caches.size());
+    assertSame(
+        mockServiceRegistry1.findMicroserviceCache(
+            MicroserviceCacheKey.builder().serviceName("svc2").appId("app").env("env").build()),
+        aggregateMicroserviceCache2.caches.get(mockServiceRegistry1.getName()));
+    assertEquals(2, aggregateServiceRegistryCache.microserviceCache.size());
+    assertNotNull(aggregateServiceRegistryCache.microserviceCache.get(
+        MicroserviceCacheKey.builder().serviceName("svc2").appId("app").env("env").build()
+    ));
+  }
+
+  @Test
+  public void findServiceCache_not_found() {
+    MicroserviceCache serviceCache = aggregateServiceRegistryCache.findServiceCache(
+        MicroserviceCacheKey.builder().serviceName("svc-not-exist").appId("app").env("env").build()
+    );
+
+    assertTrue(serviceCache instanceof AggregateMicroserviceCache);
+    assertEquals(MicroserviceCacheStatus.SERVICE_NOT_FOUND, serviceCache.getStatus());
+    AggregateMicroserviceCache aggregateMicroserviceCache = (AggregateMicroserviceCache) serviceCache;
+    assertEquals(0, aggregateMicroserviceCache.caches.size());
+    assertEquals(3, aggregateMicroserviceCache.serviceRegistries.size());
+    // should remove the cache of not existing microservice
+    assertEquals(0, aggregateServiceRegistryCache.microserviceCache.size());
+  }
+
+  @Test
+  public void onMicroserviceCacheRefreshed() {
+    MicroserviceCacheKey microserviceCacheKey =
+        MicroserviceCacheKey.builder().serviceName("svc").appId("app").env("env").build();
+    MicroserviceCacheKey microserviceCacheKey2 =
+        MicroserviceCacheKey.builder().serviceName("svc2").appId("app").env("env").build();
+    aggregateServiceRegistryCache.onMicroserviceCacheRefreshed(new MicroserviceCacheRefreshedEvent(
+        Collections.singletonList(
+            new MockMicroserviceCache(
+                microserviceCacheKey,
+                MicroserviceCacheStatus.REFRESHED
+            )
+        )
+    ));
+
+    assertTrue(aggregateServiceRegistryCache.microserviceCache.isEmpty());
+
+    MicroserviceCache serviceCache = aggregateServiceRegistryCache.findServiceCache(microserviceCacheKey);
+    MicroserviceCache serviceCache2 = aggregateServiceRegistryCache.findServiceCache(microserviceCacheKey2);
+
+    assertEquals("1", serviceCache.getRevisionId());
+    assertEquals("1", serviceCache2.getRevisionId());
+
+    aggregateServiceRegistryCache.onMicroserviceCacheRefreshed(new MicroserviceCacheRefreshedEvent(
+        Collections.singletonList(
+            new MockMicroserviceCache(
+                microserviceCacheKey,
+                MicroserviceCacheStatus.REFRESHED
+            )
+        )
+    ));
+
+    assertEquals("2", serviceCache.getRevisionId());
+    assertEquals("1", serviceCache2.getRevisionId());
+
+    // test watcher
+    ArrayList<Object> refreshedCaches = new ArrayList<>();
+    aggregateServiceRegistryCache.setCacheRefreshedWatcher(refreshedCaches::addAll);
+
+    aggregateServiceRegistryCache.onMicroserviceCacheRefreshed(new MicroserviceCacheRefreshedEvent(
+        Arrays.asList(
+            new MockMicroserviceCache(
+                microserviceCacheKey,
+                MicroserviceCacheStatus.REFRESHED
+            ),
+            new MockMicroserviceCache(
+                microserviceCacheKey2,
+                MicroserviceCacheStatus.REFRESHED
+            )
+        )
+    ));
+
+    assertEquals("3", serviceCache.getRevisionId());
+    assertEquals("2", serviceCache2.getRevisionId());
+    assertEquals(2, refreshedCaches.size());
+    assertSame(serviceCache, refreshedCaches.get(0));
+    assertSame(serviceCache2, refreshedCaches.get(1));
+
+    refreshedCaches.clear();
+
+    // test removing not existing service cache
+    ((MockMicroserviceCache) mockServiceRegistry0.findMicroserviceCache(microserviceCacheKey))
+        .setStatus(MicroserviceCacheStatus.SERVICE_NOT_FOUND);
+    ((MockMicroserviceCache) mockServiceRegistry1.findMicroserviceCache(microserviceCacheKey))
+        .setStatus(MicroserviceCacheStatus.SERVICE_NOT_FOUND);
+    aggregateServiceRegistryCache.onMicroserviceCacheRefreshed(new MicroserviceCacheRefreshedEvent(
+        Arrays.asList(
+            new MockMicroserviceCache(
+                microserviceCacheKey,
+                MicroserviceCacheStatus.REFRESHED
+            ),
+            new MockMicroserviceCache(
+                microserviceCacheKey2,
+                MicroserviceCacheStatus.REFRESHED
+            )
+        )
+    ));
+
+    assertEquals("4", serviceCache.getRevisionId());
+    assertEquals("3", serviceCache2.getRevisionId());
+    assertEquals(2, refreshedCaches.size());
+    assertSame(serviceCache, refreshedCaches.get(0));
+    assertSame(serviceCache2, refreshedCaches.get(1));
+    assertEquals(MicroserviceCacheStatus.SERVICE_NOT_FOUND, serviceCache.getStatus());
+    // not existing service cache removed, only serviceCache2 is left
+    assertEquals(1, aggregateServiceRegistryCache.microserviceCache.size());
+    assertSame(serviceCache2, aggregateServiceRegistryCache.microserviceCache.get(microserviceCacheKey2));
+  }
+}
\ No newline at end of file
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheKeyTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheKeyTest.java
new file mode 100644
index 0000000..b38f83e
--- /dev/null
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/MicroserviceCacheKeyTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.serviceregistry.registry.cache;
+
+import static org.junit.Assert.fail;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class MicroserviceCacheKeyTest {
+
+  @Test
+  public void constructors() {
+    checkConstructorException(null, "appId", "svc", "microserviceCacheKey.env is null");
+    checkConstructorException("env", null, "svc", "microserviceCacheKey.appId is null");
+    checkConstructorException("env", "appId", null, "microserviceCacheKey.serviceName is null");
+
+    MicroserviceCacheKey microserviceCacheKey =
+        MicroserviceCacheKey.builder().serviceName("svc").appId("app").env("env").build();
+    Assert.assertEquals("svc", microserviceCacheKey.getServiceName());
+    Assert.assertEquals("app", microserviceCacheKey.getAppId());
+    Assert.assertEquals("env", microserviceCacheKey.getEnv());
+    Assert.assertEquals("svc@app@env", microserviceCacheKey.toString());
+
+    microserviceCacheKey =
+        MicroserviceCacheKey.builder().serviceName("app:svc").appId("app").env("env").build();
+    Assert.assertEquals("svc", microserviceCacheKey.getServiceName());
+    Assert.assertEquals("app", microserviceCacheKey.getAppId());
+    Assert.assertEquals("env", microserviceCacheKey.getEnv());
+
+    microserviceCacheKey =
+        MicroserviceCacheKey.builder().serviceName("app2:svc").appId("app").env("env").build();
+    Assert.assertEquals("svc", microserviceCacheKey.getServiceName());
+    Assert.assertEquals("app2", microserviceCacheKey.getAppId());
+    Assert.assertEquals("env", microserviceCacheKey.getEnv());
+  }
+
+  private void checkConstructorException(String env, String appId, String svc, String expectedMessage) {
+    try {
+      MicroserviceCacheKey.builder().env(env).appId(appId).serviceName(svc).build();
+      fail("an Exception is expected!");
+    } catch (Exception e) {
+      Assert.assertEquals(expectedMessage, e.getMessage());
+    }
+  }
+
+  @Test
+  public void equals_and_hashcode() {
+    MicroserviceCacheKey microserviceCacheKey =
+        MicroserviceCacheKey.builder().env("env").appId("app").serviceName("svc").build();
+    MicroserviceCacheKey microserviceCacheKey2 =
+        MicroserviceCacheKey.builder().env("env").appId("app").serviceName("svc").build();
+    Assert.assertEquals(microserviceCacheKey, microserviceCacheKey2);
+    Assert.assertEquals(microserviceCacheKey.hashCode(), microserviceCacheKey2.hashCode());
+
+    microserviceCacheKey2 =
+        MicroserviceCacheKey.builder().env("env1").appId("app").serviceName("svc").build();
+    Assert.assertNotEquals(microserviceCacheKey, microserviceCacheKey2);
+    microserviceCacheKey2 =
+        MicroserviceCacheKey.builder().env("env").appId("app1").serviceName("svc").build();
+    Assert.assertNotEquals(microserviceCacheKey, microserviceCacheKey2);
+    microserviceCacheKey2 =
+        MicroserviceCacheKey.builder().env("env").appId("app").serviceName("svc1").build();
+    Assert.assertNotEquals(microserviceCacheKey, microserviceCacheKey2);
+  }
+
+  @Test
+  public void plainKey() {
+    MicroserviceCacheKey microserviceCacheKey =
+        MicroserviceCacheKey.builder().env("env").appId("app").serviceName("svc").build();
+    Assert.assertEquals("svc@app@env", microserviceCacheKey.plainKey());
+  }
+}
\ No newline at end of file
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/MockedMicroserviceCache.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/MockedMicroserviceCache.java
new file mode 100644
index 0000000..4d40731
--- /dev/null
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/MockedMicroserviceCache.java
@@ -0,0 +1,49 @@
+/*
+ * 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.serviceregistry.registry.cache;
+
+import java.util.List;
+
+import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
+import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient;
+
+public class MockedMicroserviceCache extends RefreshableMicroserviceCache {
+  public MockedMicroserviceCache() {
+    super(null, null, null, false);
+  }
+
+  public MockedMicroserviceCache(Microservice consumerService, MicroserviceCacheKey key,
+      ServiceRegistryClient srClient,
+      boolean emptyInstanceProtectionEnabled) {
+    super(consumerService, key, srClient, emptyInstanceProtectionEnabled);
+  }
+
+  @Override
+  public void setStatus(MicroserviceCacheStatus status) {
+    super.setStatus(status);
+  }
+
+  public void setInstances(List<MicroserviceInstance> instances) {
+    this.instances = instances;
+  }
+
+  public void setRevisionId(String revisionId) {
+    this.revisionId = revisionId;
+  }
+}
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableMicroserviceCacheTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableMicroserviceCacheTest.java
new file mode 100644
index 0000000..0486e00
--- /dev/null
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableMicroserviceCacheTest.java
@@ -0,0 +1,367 @@
+/*
+ * 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.serviceregistry.registry.cache;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Function;
+
+import org.apache.servicecomb.foundation.common.Holder;
+import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
+import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+import org.apache.servicecomb.serviceregistry.api.response.FindInstancesResponse;
+import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient;
+import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances;
+import org.apache.servicecomb.serviceregistry.consumer.MicroserviceInstancePing;
+import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache.MicroserviceCacheStatus;
+import org.apache.servicecomb.serviceregistry.task.event.SafeModeChangeEvent;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import mockit.Mock;
+import mockit.MockUp;
+
+public class RefreshableMicroserviceCacheTest {
+
+  private Holder<Function<Object[], MicroserviceInstances>> findServiceInstancesOprHolder = new Holder<>();
+
+  private ServiceRegistryClient srClient;
+
+  private RefreshableMicroserviceCache microserviceCache;
+
+  private List<MicroserviceInstance> pulledInstances = new ArrayList<>();
+
+  private Microservice consumerService;
+
+  @Before
+  public void setUp() throws Exception {
+    srClient = new MockUp<ServiceRegistryClient>() {
+      @Mock
+      MicroserviceInstances findServiceInstances(String consumerId, String appId, String serviceName,
+          String versionRule, String revision) {
+        return findServiceInstancesOprHolder.value
+            .apply(new Object[] {consumerId, appId, serviceName, versionRule, revision});
+      }
+    }.getMockInstance();
+    consumerService = new Microservice();
+    consumerService.setServiceId("consumerId");
+    microserviceCache = new RefreshableMicroserviceCache(
+        consumerService,
+        MicroserviceCacheKey.builder().env("env").appId("app").serviceName("svc").build(),
+        srClient,
+        false);
+
+    findServiceInstancesOprHolder.value = params -> {
+      MicroserviceInstances microserviceInstances = new MicroserviceInstances();
+      microserviceInstances.setNeedRefresh(true);
+      microserviceInstances.setRevision("rev0");
+      microserviceInstances.setMicroserviceNotExist(false);
+
+      FindInstancesResponse instancesResponse = new FindInstancesResponse();
+      instancesResponse.setInstances(pulledInstances);
+      microserviceInstances.setInstancesResponse(instancesResponse);
+
+      return microserviceInstances;
+    };
+  }
+
+  @Test
+  public void forceRefresh() {
+    MicroserviceInstance microserviceInstance = new MicroserviceInstance();
+    microserviceInstance.setInstanceId("instanceId00");
+    ArrayList<MicroserviceInstance> instances = new ArrayList<>();
+    instances.add(microserviceInstance);
+    findServiceInstancesOprHolder.value = params -> {
+      Assert.assertEquals("consumerId", params[0]);
+      Assert.assertEquals("app", params[1]);
+      Assert.assertEquals("svc", params[2]);
+      Assert.assertEquals("0.0.0.0+", params[3]);
+      Assert.assertNull(params[4]);
+      MicroserviceInstances microserviceInstances = new MicroserviceInstances();
+      microserviceInstances.setNeedRefresh(true);
+      microserviceInstances.setRevision("rev2");
+      microserviceInstances.setMicroserviceNotExist(false);
+
+      FindInstancesResponse instancesResponse = new FindInstancesResponse();
+      instancesResponse.setInstances(instances);
+
+      microserviceInstances.setInstancesResponse(instancesResponse);
+      return microserviceInstances;
+    };
+
+    microserviceCache.revisionId = "rev";
+    microserviceCache.forceRefresh();
+
+    Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus());
+    List<MicroserviceInstance> cachedInstances = microserviceCache.getInstances();
+    Assert.assertEquals(1, cachedInstances.size());
+    MicroserviceInstance instance = cachedInstances.iterator().next();
+    Assert.assertEquals("instanceId00", instance.getInstanceId());
+    Assert.assertEquals("rev2", microserviceCache.getRevisionId());
+  }
+
+  @Test
+  public void refresh() {
+    ArrayList<MicroserviceInstance> instances = new ArrayList<>();
+    findServiceInstancesOprHolder.value = params -> {
+      Assert.assertEquals("consumerId", params[0]);
+      Assert.assertEquals("app", params[1]);
+      Assert.assertEquals("svc", params[2]);
+      Assert.assertEquals("0.0.0.0+", params[3]);
+      Assert.assertNull(params[4]);
+      MicroserviceInstances microserviceInstances = new MicroserviceInstances();
+      microserviceInstances.setNeedRefresh(true);
+      microserviceInstances.setRevision("rev0");
+      microserviceInstances.setMicroserviceNotExist(false);
+
+      FindInstancesResponse instancesResponse = new FindInstancesResponse();
+      instancesResponse.setInstances(instances);
+
+      microserviceInstances.setInstancesResponse(instancesResponse);
+      return microserviceInstances;
+    };
+
+    // at the beginning, no instances in cache
+    List<MicroserviceInstance> cachedInstances = microserviceCache.getInstances();
+    Assert.assertEquals(0, cachedInstances.size());
+    Assert.assertNull(microserviceCache.getRevisionId());
+
+    // find 1 instance from sc
+    MicroserviceInstance microserviceInstance = new MicroserviceInstance();
+    instances.add(microserviceInstance);
+    microserviceInstance.setInstanceId("instanceId00");
+
+    microserviceCache.refresh();
+    Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus());
+
+    cachedInstances = microserviceCache.getInstances();
+    Assert.assertEquals(1, cachedInstances.size());
+    MicroserviceInstance instance = cachedInstances.iterator().next();
+    Assert.assertEquals("instanceId00", instance.getInstanceId());
+    Assert.assertEquals("rev0", microserviceCache.getRevisionId());
+
+    // 2nd time, find 2 instances, one of them is the old instance
+    MicroserviceInstance microserviceInstance1 = new MicroserviceInstance();
+    instances.add(microserviceInstance1);
+    microserviceInstance1.setInstanceId("instanceId01");
+
+    findServiceInstancesOprHolder.value = params -> {
+      Assert.assertEquals("consumerId", params[0]);
+      Assert.assertEquals("app", params[1]);
+      Assert.assertEquals("svc", params[2]);
+      Assert.assertEquals("0.0.0.0+", params[3]);
+      Assert.assertEquals("rev0", params[4]);
+      MicroserviceInstances microserviceInstances = new MicroserviceInstances();
+      microserviceInstances.setNeedRefresh(true);
+      microserviceInstances.setRevision("rev1");
+      microserviceInstances.setMicroserviceNotExist(false);
+
+      FindInstancesResponse instancesResponse = new FindInstancesResponse();
+      instancesResponse.setInstances(instances);
+
+      microserviceInstances.setInstancesResponse(instancesResponse);
+      return microserviceInstances;
+    };
+
+    microserviceCache.refresh();
+    Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus());
+    cachedInstances = microserviceCache.getInstances();
+    Assert.assertEquals(2, cachedInstances.size());
+    Assert.assertEquals("instanceId00", cachedInstances.get(0).getInstanceId());
+    Assert.assertEquals("instanceId01", cachedInstances.get(1).getInstanceId());
+  }
+
+  @Test
+  public void refresh_service_error() {
+    findServiceInstancesOprHolder.value = params -> null;
+
+    List<MicroserviceInstance> oldInstanceList = microserviceCache.getInstances();
+
+    microserviceCache.refresh();
+    Assert.assertEquals(MicroserviceCacheStatus.CLIENT_ERROR, microserviceCache.getStatus());
+    Assert.assertSame(oldInstanceList, microserviceCache.getInstances());
+  }
+
+  @Test
+  public void refresh_service_not_exist() {
+    findServiceInstancesOprHolder.value = params -> {
+      MicroserviceInstances microserviceInstances = new MicroserviceInstances();
+      microserviceInstances.setMicroserviceNotExist(true);
+      return microserviceInstances;
+    };
+
+    List<MicroserviceInstance> oldInstanceList = microserviceCache.getInstances();
+
+    microserviceCache.refresh();
+    Assert.assertEquals(MicroserviceCacheStatus.SERVICE_NOT_FOUND, microserviceCache.getStatus());
+    Assert.assertSame(oldInstanceList, microserviceCache.getInstances());
+  }
+
+  @Test
+  public void refresh_service_no_change() {
+    findServiceInstancesOprHolder.value = params -> {
+      MicroserviceInstances microserviceInstances = new MicroserviceInstances();
+      microserviceInstances.setMicroserviceNotExist(false);
+      microserviceInstances.setNeedRefresh(false);
+      return microserviceInstances;
+    };
+
+    List<MicroserviceInstance> oldInstanceList = microserviceCache.getInstances();
+
+    microserviceCache.refresh();
+    Assert.assertEquals(MicroserviceCacheStatus.NO_CHANGE, microserviceCache.getStatus());
+    Assert.assertSame(oldInstanceList, microserviceCache.getInstances());
+  }
+
+  @Test
+  public void refresh_error_in_setInstances() {
+    microserviceCache = new RefreshableMicroserviceCache(
+        consumerService,
+        MicroserviceCacheKey.builder().env("env").appId("app").serviceName("svc").build(),
+        srClient,
+        false) {
+      @Override
+      protected Set<MicroserviceInstance> mergeInstances(List<MicroserviceInstance> pulledInstances) {
+        throw new IllegalStateException("a mock exception");
+      }
+    };
+
+    List<MicroserviceInstance> oldInstanceList = microserviceCache.getInstances();
+    Assert.assertEquals(MicroserviceCacheStatus.INIT, microserviceCache.getStatus());
+
+    microserviceCache.refresh();
+
+    Assert.assertEquals(MicroserviceCacheStatus.SETTING_CACHE_ERROR, microserviceCache.getStatus());
+    List<MicroserviceInstance> newInstanceList = microserviceCache.getInstances();
+    Assert.assertEquals(0, newInstanceList.size());
+    Assert.assertSame(oldInstanceList, newInstanceList);
+  }
+
+  @Test
+  public void refresh_safe_mode() {
+    microserviceCache.instances = new ArrayList<>();
+    MicroserviceInstance instance0 = new MicroserviceInstance();
+    instance0.setInstanceId("instanceId0");
+    microserviceCache.instances.add(instance0);
+
+    pulledInstances = new ArrayList<>();
+    MicroserviceInstance instance1 = new MicroserviceInstance();
+    instance1.setInstanceId("instanceId1");
+    pulledInstances.add(instance1);
+
+    microserviceCache.refresh();
+
+    Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus());
+    Assert.assertEquals(1, microserviceCache.getInstances().size());
+    Assert.assertEquals("instanceId1", microserviceCache.getInstances().get(0).getInstanceId());
+
+    // enter safe mode
+    microserviceCache.onSafeModeChanged(new SafeModeChangeEvent(true));
+
+    pulledInstances = new ArrayList<>();
+    MicroserviceInstance instance2 = new MicroserviceInstance();
+    instance2.setInstanceId("instanceId2");
+    pulledInstances.add(instance2);
+
+    microserviceCache.refresh();
+
+    Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus());
+    Assert.assertEquals(2, microserviceCache.getInstances().size());
+    Assert.assertEquals("instanceId2", microserviceCache.getInstances().get(0).getInstanceId());
+    Assert.assertEquals("instanceId1", microserviceCache.getInstances().get(1).getInstanceId());
+
+    // exit safe mode
+    microserviceCache.onSafeModeChanged(new SafeModeChangeEvent(false));
+
+    pulledInstances = new ArrayList<>();
+    MicroserviceInstance instance3 = new MicroserviceInstance();
+    instance3.setInstanceId("instanceId3");
+    pulledInstances.add(instance3);
+
+    microserviceCache.refresh();
+
+    Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus());
+    Assert.assertEquals(1, microserviceCache.getInstances().size());
+    Assert.assertEquals("instanceId3", microserviceCache.getInstances().get(0).getInstanceId());
+  }
+
+  @Test
+  public void refresh_empty_instance_protection_disabled() {
+    microserviceCache.instances = new ArrayList<>();
+    MicroserviceInstance instance0 = new MicroserviceInstance();
+    instance0.setInstanceId("instanceId0");
+    microserviceCache.instances.add(instance0);
+
+    pulledInstances = new ArrayList<>();
+    microserviceCache.refresh();
+
+    Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus());
+    Assert.assertEquals(0, microserviceCache.getInstances().size());
+  }
+
+  @Test
+  public void refresh_empty_instance_protection_enabled() {
+    microserviceCache.setEmptyInstanceProtectionEnabled(true);
+    microserviceCache.instancePing = new MicroserviceInstancePing() {
+      @Override
+      public int getOrder() {
+        return 0;
+      }
+
+      @Override
+      public boolean ping(MicroserviceInstance instance) {
+        return true;
+      }
+    };
+    microserviceCache.instances = new ArrayList<>();
+    MicroserviceInstance instance0 = new MicroserviceInstance();
+    instance0.setInstanceId("instanceId0");
+    microserviceCache.instances.add(instance0);
+
+    pulledInstances = new ArrayList<>();
+    microserviceCache.refresh();
+
+    Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus());
+    Assert.assertEquals(1, microserviceCache.getInstances().size());
+    Assert.assertEquals("instanceId0", microserviceCache.getInstances().get(0).getInstanceId());
+  }
+
+  @Test
+  public void set_consumer_service_id() {
+    Holder<Integer> assertCounter = new Holder<>(0);
+    Function<Object[], MicroserviceInstances> preservedLogic = findServiceInstancesOprHolder.value;
+    findServiceInstancesOprHolder.value = params -> {
+      Assert.assertEquals("consumerId", params[0]);
+      assertCounter.value++;
+      return preservedLogic.apply(params);
+    };
+    microserviceCache.refresh();
+
+    consumerService.setServiceId("consumerId2");
+
+    findServiceInstancesOprHolder.value = params -> {
+      Assert.assertEquals("consumerId2", params[0]);
+      assertCounter.value++;
+      return preservedLogic.apply(params);
+    };
+    microserviceCache.refresh();
+    Assert.assertEquals(Integer.valueOf(2), assertCounter.value);
+  }
+}
\ No newline at end of file
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableServiceRegistryCacheTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableServiceRegistryCacheTest.java
new file mode 100644
index 0000000..af6e9d3
--- /dev/null
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/cache/RefreshableServiceRegistryCacheTest.java
@@ -0,0 +1,205 @@
+/*
+ * 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.serviceregistry.registry.cache;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.function.Function;
+
+import org.apache.servicecomb.foundation.common.Holder;
+import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
+import org.apache.servicecomb.serviceregistry.api.response.FindInstancesResponse;
+import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances;
+import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache.MicroserviceCacheStatus;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class RefreshableServiceRegistryCacheTest {
+
+  private Holder<Function<String, MicroserviceInstances>> pullInstanceFromServiceCenterLogic = new Holder<>(
+      rev -> {
+        MicroserviceInstances microserviceInstances = new MicroserviceInstances();
+        microserviceInstances.setMicroserviceNotExist(false);
+        microserviceInstances.setNeedRefresh(true);
+        microserviceInstances.setRevision(rev);
+        FindInstancesResponse instancesResponse = new FindInstancesResponse();
+        instancesResponse.setInstances(new ArrayList<>());
+        microserviceInstances.setInstancesResponse(instancesResponse);
+        return microserviceInstances;
+      }
+  );
+
+  private RefreshableServiceRegistryCache serviceRegistryCache;
+
+  private Microservice consumerService;
+
+  @Before
+  public void setUp() throws Exception {
+    serviceRegistryCache = new RefreshableServiceRegistryCache(consumerService, null) {
+      @Override
+      RefreshableMicroserviceCache createMicroserviceCache(MicroserviceCacheKey microserviceCacheKey) {
+        return new RefreshableMicroserviceCache(consumerService, microserviceCacheKey, null, false) {
+          @Override
+          MicroserviceInstances pullInstanceFromServiceCenter(String revisionId) {
+            return pullInstanceFromServiceCenterLogic.value.apply(revisionId);
+          }
+        };
+      }
+    };
+    consumerService = new Microservice();
+    consumerService.setServiceId("testConsumer");
+  }
+
+  @Test
+  public void find_service_instances() {
+    MicroserviceCache microserviceCache = serviceRegistryCache
+        .findServiceCache(MicroserviceCacheKey.builder().serviceName("svc").appId("app").env("env").build());
+
+    Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, microserviceCache.getStatus());
+    Assert.assertEquals(0, microserviceCache.getInstances().size());
+    Assert.assertEquals(1, serviceRegistryCache.microserviceCache.size());
+    Entry<MicroserviceCacheKey, RefreshableMicroserviceCache> cacheEntry =
+        serviceRegistryCache.microserviceCache.entrySet().iterator().next();
+    Assert.assertEquals(MicroserviceCacheKey.builder().serviceName("svc").appId("app").env("env").build(),
+        cacheEntry.getKey());
+  }
+
+  @Test
+  public void refreshCache() {
+    RefreshableMicroserviceCache microserviceCache = new RefreshableMicroserviceCache(
+        consumerService,
+        MicroserviceCacheKey.builder().serviceName("svc").appId("appId").env("env").build(),
+        null, false) {
+      @Override
+      public void refresh() {
+        this.status = MicroserviceCacheStatus.REFRESHED;
+      }
+    };
+    RefreshableMicroserviceCache microserviceCache2 = new RefreshableMicroserviceCache(
+        consumerService,
+        MicroserviceCacheKey.builder().serviceName("svc2").appId("appId").env("env").build(),
+        null, false);
+    RefreshableMicroserviceCache microserviceCache3 = new RefreshableMicroserviceCache(
+        consumerService,
+        MicroserviceCacheKey.builder().serviceName("svc3").appId("appId").env("env").build(),
+        null, false) {
+      @Override
+      public void refresh() {
+        this.status = MicroserviceCacheStatus.SERVICE_NOT_FOUND;
+      }
+    };
+
+    serviceRegistryCache.microserviceCache.put(microserviceCache.getKey(), microserviceCache);
+    serviceRegistryCache.microserviceCache.put(microserviceCache2.getKey(), microserviceCache2);
+    serviceRegistryCache.microserviceCache.put(microserviceCache3.getKey(), microserviceCache3);
+
+    List<MicroserviceCache> refreshedCaches = new ArrayList<>();
+    serviceRegistryCache.setCacheRefreshedWatcher(refreshedCaches::addAll);
+
+    serviceRegistryCache.refreshCache();
+
+    Assert.assertEquals(2, refreshedCaches.size());
+    Assert.assertSame(microserviceCache.getKey(), refreshedCaches.get(0).getKey());
+    Assert.assertSame(microserviceCache3.getKey(), refreshedCaches.get(1).getKey());
+    Assert.assertEquals(2, serviceRegistryCache.microserviceCache.size());
+    Assert.assertSame(microserviceCache, serviceRegistryCache.microserviceCache.get(microserviceCache.getKey()));
+    Assert.assertSame(microserviceCache2, serviceRegistryCache.microserviceCache.get(microserviceCache2.getKey()));
+  }
+
+  @Test
+  public void forceRefreshCache() {
+    RefreshableMicroserviceCache microserviceCache = new RefreshableMicroserviceCache(
+        consumerService,
+        MicroserviceCacheKey.builder().serviceName("svc").appId("appId").env("env").build(),
+        null, false) {
+      @Override
+      public void forceRefresh() {
+        this.status = MicroserviceCacheStatus.REFRESHED;
+      }
+    };
+
+    serviceRegistryCache.microserviceCache.put(microserviceCache.getKey(), microserviceCache);
+
+    List<MicroserviceCache> refreshedCaches = new ArrayList<>();
+    serviceRegistryCache.setCacheRefreshedWatcher(refreshedCaches::addAll);
+
+    serviceRegistryCache.forceRefreshCache();
+
+    Assert.assertEquals(1, refreshedCaches.size());
+    Assert.assertSame(microserviceCache.getKey(), refreshedCaches.get(0).getKey());
+  }
+
+  @Test
+  public void findServiceCache_normal() {
+    mockServiceRegistryHolder().value = MicroserviceCacheStatus.REFRESHED;
+
+    MicroserviceCacheKey cacheKey = MicroserviceCacheKey.builder().serviceName("svc").appId("app").env("env").build();
+    MicroserviceCache serviceCache = serviceRegistryCache.findServiceCache(cacheKey);
+
+    Assert.assertSame(cacheKey, serviceCache.getKey());
+    Assert.assertEquals(MicroserviceCacheStatus.REFRESHED, serviceCache.getStatus());
+    Assert.assertEquals(1, serviceRegistryCache.microserviceCache.size());
+    Assert.assertSame(serviceCache, serviceRegistryCache.microserviceCache.get(cacheKey));
+  }
+
+  @Test
+  public void findServiceCache_client_error() {
+    mockServiceRegistryHolder().value = MicroserviceCacheStatus.CLIENT_ERROR;
+
+    MicroserviceCacheKey cacheKey = MicroserviceCacheKey.builder().serviceName("svc").appId("app").env("env").build();
+    MicroserviceCache serviceCache = serviceRegistryCache.findServiceCache(cacheKey);
+
+    Assert.assertSame(cacheKey, serviceCache.getKey());
+    Assert.assertEquals(MicroserviceCacheStatus.CLIENT_ERROR, serviceCache.getStatus());
+    Assert.assertEquals(1, serviceRegistryCache.microserviceCache.size());
+    Assert.assertSame(serviceCache, serviceRegistryCache.microserviceCache.get(cacheKey));
+  }
+
+  @Test
+  public void findServiceCache_service_not_found() {
+    mockServiceRegistryHolder().value = MicroserviceCacheStatus.SERVICE_NOT_FOUND;
+
+    MicroserviceCacheKey cacheKey = MicroserviceCacheKey.builder().serviceName("svc").appId("app").env("env").build();
+    MicroserviceCache serviceCache = serviceRegistryCache.findServiceCache(cacheKey);
+
+    Assert.assertSame(cacheKey, serviceCache.getKey());
+    Assert.assertEquals(MicroserviceCacheStatus.SERVICE_NOT_FOUND, serviceCache.getStatus());
+    Assert.assertTrue(serviceRegistryCache.microserviceCache.isEmpty());
+  }
+
+  private Holder<MicroserviceCacheStatus> mockServiceRegistryHolder() {
+    Holder<MicroserviceCacheStatus> statusHolder = new Holder<>();
+    serviceRegistryCache = new RefreshableServiceRegistryCache(consumerService, null) {
+      @Override
+      RefreshableMicroserviceCache createMicroserviceCache(MicroserviceCacheKey microserviceCacheKey) {
+        return new RefreshableMicroserviceCache(
+            consumerService,
+            microserviceCacheKey,
+            null, false) {
+          @Override
+          public void refresh() {
+            this.status = statusHolder.value;
+          }
+        };
+      }
+    };
+    return statusHolder;
+  }
+}
\ No newline at end of file


[servicecomb-java-chassis] 07/19: [SCB-1691] add WebsocketClientPool for multiple ServiceRegistryClient instance situation

Posted by ya...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

yaohaishi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit 32cf126afb58107a0a07e99398e410b63cdb9bf2
Author: yhs0092 <yh...@163.com>
AuthorDate: Wed Jan 15 10:07:45 2020 +0800

    [SCB-1691] add WebsocketClientPool for multiple ServiceRegistryClient instance situation
    
    the legacy WebsocketUtils is preserved for compatibility and marked deprecated
---
 .../client/http/HttpClientPool.java                |   3 -
 .../client/http/RestClientUtil.java                |   6 +-
 .../client/http/WebsocketClientPool.java           |   6 +-
 .../client/http/WebsocketClientUtil.java           | 126 +++++++++++++++++++++
 .../client/http/WebsocketUtils.java                |   4 +-
 5 files changed, 135 insertions(+), 10 deletions(-)

diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/HttpClientPool.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/HttpClientPool.java
index 46ca5ef..f4d28c8 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/HttpClientPool.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/HttpClientPool.java
@@ -27,9 +27,6 @@ import io.vertx.core.http.HttpClientOptions;
 import io.vertx.core.http.HttpVersion;
 import io.vertx.core.net.ProxyOptions;
 
-/**
- * Created by on 2017/4/28.
- */
 final class HttpClientPool extends AbstractClientPool {
 
   private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientPool.class);
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestClientUtil.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestClientUtil.java
index 568ab57..6f0e8b0 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestClientUtil.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestClientUtil.java
@@ -43,11 +43,11 @@ import io.vertx.core.http.HttpMethod;
 final class RestClientUtil {
   private static final Logger LOGGER = LoggerFactory.getLogger(RestClientUtil.class);
 
-  private static final String HEADER_CONTENT_TYPE = "Content-Type";
+  static final String HEADER_CONTENT_TYPE = "Content-Type";
 
-  private static final String HEADER_USER_AGENT = "User-Agent";
+  static final String HEADER_USER_AGENT = "User-Agent";
 
-  private static final String HEADER_TENANT_NAME = "x-domain-name";
+  static final String HEADER_TENANT_NAME = "x-domain-name";
 
   private List<AuthHeaderProvider> authHeaderProviders;
 
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientPool.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientPool.java
index 802867a..38c17be 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientPool.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientPool.java
@@ -25,13 +25,13 @@ import org.slf4j.LoggerFactory;
 import io.vertx.core.http.HttpClientOptions;
 import io.vertx.core.http.HttpVersion;
 
-/**
- * Created by on 2017/4/28.
- */
 public final class WebsocketClientPool extends AbstractClientPool {
 
   private static final Logger LOGGER = LoggerFactory.getLogger(WebsocketClientPool.class);
 
+  /**
+   * The default instance, for default sc cluster.
+   */
   public static final WebsocketClientPool INSTANCE = new WebsocketClientPool();
 
   private WebsocketClientPool() {
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientUtil.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientUtil.java
new file mode 100644
index 0000000..9262752
--- /dev/null
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientUtil.java
@@ -0,0 +1,126 @@
+/*
+ * 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.serviceregistry.client.http;
+
+import java.io.ByteArrayInputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.servicecomb.foundation.auth.AuthHeaderProvider;
+import org.apache.servicecomb.foundation.auth.SignRequest;
+import org.apache.servicecomb.foundation.common.net.IpPort;
+import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext;
+import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.vertx.core.Handler;
+import io.vertx.core.MultiMap;
+import io.vertx.core.buffer.Buffer;
+import io.vertx.core.http.CaseInsensitiveHeaders;
+import io.vertx.core.http.HttpMethod;
+import io.vertx.core.http.WebSocketConnectOptions;
+
+public final class WebsocketClientUtil {
+  private static final Logger LOGGER = LoggerFactory.getLogger(WebsocketClientUtil.class);
+
+  private WebsocketClientPool websocketClientPool;
+
+  private List<AuthHeaderProvider> authHeaderProviders;
+
+  WebsocketClientUtil(ServiceRegistryConfig serviceRegistryConfig) {
+    websocketClientPool = new WebsocketClientPool(serviceRegistryConfig);
+    authHeaderProviders = serviceRegistryConfig.getAuthHeaderProviders();
+  }
+
+  public void open(IpPort ipPort, String url, Handler<Void> onOpen, Handler<Void> onClose,
+      Handler<Buffer> onMessage, Handler<Throwable> onException,
+      Handler<Throwable> onConnectFailed) {
+    HttpClientWithContext vertxHttpClient = websocketClientPool.getClient();
+    vertxHttpClient.runOnContext(client -> {
+      WebSocketConnectOptions options = new WebSocketConnectOptions();
+      options.setHost(ipPort.getHostOrIp()).setPort(ipPort.getPort()).setURI(url)
+          .setHeaders(getDefaultHeaders().addAll(getSignAuthHeaders(
+              createSignRequest(HttpMethod.GET.name(), ipPort, new RequestParam(), url, new HashMap<>()))));
+      client.webSocket(options, asyncResult -> {
+        if (asyncResult.failed()) {
+          onConnectFailed.handle(asyncResult.cause());
+        } else {
+          onOpen.handle(null);
+          asyncResult.result().exceptionHandler(v -> {
+            onException.handle(v);
+            try {
+              asyncResult.result().close();
+            } catch (Exception err) {
+              LOGGER.error("ws close error.", err);
+            }
+          });
+          asyncResult.result().closeHandler(v -> {
+            onClose.handle(v);
+          });
+          asyncResult.result().pongHandler(pong -> {
+            // ignore, just prevent NPE.
+          });
+          asyncResult.result().frameHandler((frame) -> onMessage.handle(frame.binaryData()));
+        }
+      });
+    });
+  }
+
+  public MultiMap getDefaultHeaders() {
+    return new CaseInsensitiveHeaders().addAll(defaultHeaders());
+  }
+
+  private Map<String, String> defaultHeaders() {
+    Map<String, String> headers = new HashMap<>();
+    headers.put(RestClientUtil.HEADER_CONTENT_TYPE, "application/json");
+    headers.put(RestClientUtil.HEADER_USER_AGENT, "cse-serviceregistry-client/1.0.0");
+    headers.put(RestClientUtil.HEADER_TENANT_NAME, ServiceRegistryConfig.INSTANCE.getTenantName());
+
+    return headers;
+  }
+
+  public Map<String, String> getSignAuthHeaders(SignRequest signReq) {
+    Map<String, String> headers = new HashMap<>();
+    authHeaderProviders.forEach(provider -> headers.putAll(provider.getSignAuthHeaders(signReq)));
+    return headers;
+  }
+
+  public SignRequest createSignRequest(String method, IpPort ipPort, RequestParam requestParam, String url,
+      Map<String, String> headers) {
+    SignRequest signReq = new SignRequest();
+    StringBuilder endpoint = new StringBuilder("https://" + ipPort.getHostOrIp());
+    endpoint.append(":" + ipPort.getPort());
+    endpoint.append(url);
+    try {
+      signReq.setEndpoint(new URI(endpoint.toString()));
+    } catch (URISyntaxException e) {
+      LOGGER.error("set uri failed, uri is {}, message: {}", endpoint.toString(), e.getMessage());
+    }
+    signReq.setContent((requestParam.getBody() != null && requestParam.getBody().length > 0)
+        ? new ByteArrayInputStream(requestParam.getBody())
+        : null);
+    signReq.setHeaders(headers);
+    signReq.setHttpMethod(method);
+    signReq.setQueryParams(requestParam.getQueryParamsMap());
+    return signReq;
+  }
+}
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketUtils.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketUtils.java
index 1426de9..d7427ff 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketUtils.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketUtils.java
@@ -30,8 +30,10 @@ import io.vertx.core.http.HttpMethod;
 import io.vertx.core.http.WebSocketConnectOptions;
 
 /**
- * Created by on 2017/4/28.
+ * This class is designed following singleton pattern, but it's not suitable for multi sc cluster occasion.
+ * @deprecated consider to use {@link WebsocketClientUtil} instead.
  */
+@Deprecated
 public final class WebsocketUtils {
   private static final Logger LOGGER = LoggerFactory.getLogger(WebsocketUtils.class);
 


[servicecomb-java-chassis] 17/19: [SCB-1691] turn instance status to DOWN and wait for a period when shutdown

Posted by ya...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

yaohaishi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit be1660f50d7965025d79b9389bff6075c88c0f34
Author: yhs0092 <yh...@163.com>
AuthorDate: Mon Feb 17 01:11:33 2020 +0800

    [SCB-1691] turn instance status to DOWN and wait for a period when shutdown
---
 .../org/apache/servicecomb/core/SCBEngine.java     | 41 ++++++++++++++++++++--
 1 file changed, 39 insertions(+), 2 deletions(-)

diff --git a/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java b/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java
index e704efe..68903e6 100644
--- a/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java
+++ b/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java
@@ -48,6 +48,7 @@ import org.apache.servicecomb.core.provider.consumer.MicroserviceReferenceConfig
 import org.apache.servicecomb.core.provider.producer.ProducerProviderManager;
 import org.apache.servicecomb.core.transport.TransportManager;
 import org.apache.servicecomb.foundation.common.VendorExtensions;
+import org.apache.servicecomb.foundation.common.concurrency.SuppressedRunnableWrapper;
 import org.apache.servicecomb.foundation.common.event.EnableExceptionPropagation;
 import org.apache.servicecomb.foundation.common.event.EventManager;
 import org.apache.servicecomb.foundation.common.log.LogMarkerLeakFixUtils;
@@ -55,6 +56,8 @@ import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
 import org.apache.servicecomb.foundation.vertx.VertxUtils;
 import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.ServiceRegistry;
+import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstanceStatus;
 import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersions;
 import org.apache.servicecomb.serviceregistry.definition.MicroserviceNameParser;
 import org.apache.servicecomb.serviceregistry.swagger.SwaggerLoader;
@@ -78,6 +81,10 @@ public class SCBEngine {
 
   static final long DEFAULT_WAIT_UP_TIMEOUT = 10_000;
 
+  static final String CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC = "servicecomb.boot.turnDown.waitInSeconds";
+
+  static final long DEFAULT_TURN_DOWN_STATUS_WAIT_SEC = 0;
+
   private static final Object initializationLock = new Object();
 
   private volatile static SCBEngine INSTANCE;
@@ -315,8 +322,8 @@ public class SCBEngine {
   private void printServiceInfo() {
     StringBuilder serviceInfo = new StringBuilder();
     serviceInfo.append("Service information is shown below:\n");
-    for (int i = 0; i < bootUpInformationCollectors.size(); i++) {
-      serviceInfo.append(bootUpInformationCollectors.get(i).collect()).append('\n');
+    for (BootUpInformationCollector bootUpInformationCollector : bootUpInformationCollectors) {
+      serviceInfo.append(bootUpInformationCollector.collect()).append('\n');
     }
     LOGGER.info(serviceInfo.toString());
   }
@@ -387,6 +394,12 @@ public class SCBEngine {
     if (shutdownHook != null) {
       Runtime.getRuntime().removeShutdownHook(shutdownHook);
     }
+
+    //Step 0: turn down the status of this instance in service center,
+    // so that the consumers can remove this instance record in advance
+    turnDownInstanceStatus();
+    blockShutDownOperationForConsumerRefresh();
+
     //Step 1: notify all component stop invoke via BEFORE_CLOSE Event
     safeTriggerEvent(EventType.BEFORE_CLOSE);
 
@@ -418,6 +431,30 @@ public class SCBEngine {
     safeTriggerEvent(EventType.AFTER_CLOSE);
   }
 
+  private void turnDownInstanceStatus() {
+    RegistryUtils.executeOnEachServiceRegistry(sr -> new SuppressedRunnableWrapper(() -> {
+      MicroserviceInstance selfInstance = sr.getMicroserviceInstance();
+      sr.getServiceRegistryClient().updateMicroserviceInstanceStatus(
+          selfInstance.getServiceId(),
+          selfInstance.getInstanceId(),
+          MicroserviceInstanceStatus.DOWN);
+    }).run());
+  }
+
+  private void blockShutDownOperationForConsumerRefresh() {
+    try {
+      long turnDownWaitSeconds = DynamicPropertyFactory.getInstance()
+          .getLongProperty(CFG_KEY_TURN_DOWN_STATUS_WAIT_SEC, DEFAULT_TURN_DOWN_STATUS_WAIT_SEC)
+          .get();
+      if (turnDownWaitSeconds <= 0) {
+        return;
+      }
+      Thread.sleep(TimeUnit.SECONDS.toMillis(turnDownWaitSeconds));
+    } catch (InterruptedException e) {
+      LOGGER.warn("failed to block the shutdown procedure", e);
+    }
+  }
+
   private void validAllInvocationFinished() throws InterruptedException {
     long start = System.currentTimeMillis();
     while (true) {


[servicecomb-java-chassis] 19/19: [SCB-1691] fix according to review opinion

Posted by ya...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

yaohaishi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit 15cb6a740e5a106e9fc6b577f7b26b365ddbd4db
Author: yhs0092 <yh...@163.com>
AuthorDate: Fri Mar 6 19:44:00 2020 +0800

    [SCB-1691] fix according to review opinion
---
 .../java/org/apache/servicecomb/serviceregistry/RegistryUtils.java  | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
index 3f99eae..28e881d 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
@@ -86,7 +86,7 @@ public final class RegistryUtils {
 
   private static final Map<String, ServiceRegistry> EXTRA_SERVICE_REGISTRIES = new LinkedHashMap<>();
 
-  static AggregateServiceRegistryCache aggregateServiceRegistryCache;
+  private static AggregateServiceRegistryCache aggregateServiceRegistryCache;
 
   private RegistryUtils() {
   }
@@ -107,9 +107,7 @@ public final class RegistryUtils {
     ArrayList<ServiceRegistry> serviceRegistries = new ArrayList<>();
     executeOnEachServiceRegistry(serviceRegistries::add);
     aggregateServiceRegistryCache = new AggregateServiceRegistryCache(serviceRegistries);
-    aggregateServiceRegistryCache.setCacheRefreshedWatcher(refreshedCaches -> {
-      appManager.pullInstances();
-    });
+    aggregateServiceRegistryCache.setCacheRefreshedWatcher(refreshedCaches -> appManager.pullInstances());
 
     executeOnEachServiceRegistry(
         serviceRegistry -> serviceRegistry


[servicecomb-java-chassis] 13/19: [SCB-1691] code improve

Posted by ya...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

yaohaishi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit b24a03799c99d8f3c729b30f37eff453d5837d18
Author: yhs0092 <yh...@163.com>
AuthorDate: Fri Feb 14 09:33:35 2020 +0800

    [SCB-1691] code improve
    
    - print subscriber's exceptions only if exceptionPropagation is enabled
    - remove unnecessary import
---
 .../apache/servicecomb/core/handler/impl/ProducerOperationHandler.java  | 1 -
 .../apache/servicecomb/foundation/common/event/SimpleSubscriber.java    | 2 +-
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/core/src/main/java/org/apache/servicecomb/core/handler/impl/ProducerOperationHandler.java b/core/src/main/java/org/apache/servicecomb/core/handler/impl/ProducerOperationHandler.java
index 7f5b549..75e7492 100644
--- a/core/src/main/java/org/apache/servicecomb/core/handler/impl/ProducerOperationHandler.java
+++ b/core/src/main/java/org/apache/servicecomb/core/handler/impl/ProducerOperationHandler.java
@@ -22,7 +22,6 @@ import java.util.concurrent.CompletableFuture;
 
 import javax.ws.rs.core.Response.Status;
 
-import org.apache.servicecomb.core.Const;
 import org.apache.servicecomb.core.Handler;
 import org.apache.servicecomb.core.Invocation;
 import org.apache.servicecomb.core.exception.ExceptionUtils;
diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/SimpleSubscriber.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/SimpleSubscriber.java
index 2ff6998..e209f44 100644
--- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/SimpleSubscriber.java
+++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/event/SimpleSubscriber.java
@@ -106,8 +106,8 @@ public class SimpleSubscriber {
     try {
       dispatcher.accept(event);
     } catch (Throwable e) {
-      LOGGER.error("event process should not throw error. ", e);
       if (enableExceptionPropagation) {
+        LOGGER.error("event process should not throw error. ", e);
         throw e;
       }
     }


[servicecomb-java-chassis] 04/19: [SCB-1691] ServiceRegistryConfig just carries config value

Posted by ya...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

yaohaishi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit 8e1f6bf4a22377b19577b3c8295fc1006fcad987
Author: yhs0092 <yh...@163.com>
AuthorDate: Sun Feb 9 23:48:00 2020 +0800

    [SCB-1691] ServiceRegistryConfig just carries config value
---
 .../config/ServiceRegistryConfig.java              | 419 ++++++++++++---------
 ...nfig.java => ServiceRegistryConfigBuilder.java} | 198 ++++------
 .../config/TestServiceRegistryConfig.java          |  12 +-
 3 files changed, 331 insertions(+), 298 deletions(-)

diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
index 9d5e440..1596077 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
@@ -17,45 +17,27 @@
 
 package org.apache.servicecomb.serviceregistry.config;
 
-import java.net.URI;
 import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
 
-import org.apache.servicecomb.deployment.Deployment;
-import org.apache.servicecomb.deployment.DeploymentProvider;
 import org.apache.servicecomb.foundation.common.net.IpPort;
-import org.apache.servicecomb.foundation.common.net.NetUtils;
 import org.apache.servicecomb.serviceregistry.ServiceRegistry;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.netflix.config.DynamicBooleanProperty;
-import com.netflix.config.DynamicIntProperty;
-import com.netflix.config.DynamicPropertyFactory;
-import com.netflix.config.DynamicStringProperty;
 
 import io.vertx.core.http.HttpVersion;
 
-/**
- * Created by   on 2016/12/23.
- */
 public final class ServiceRegistryConfig {
-  private static final Logger LOGGER = LoggerFactory.getLogger(ServiceRegistryConfig.class);
-
-  public static final ServiceRegistryConfig INSTANCE = new ServiceRegistryConfig();
+  public static final ServiceRegistryConfig INSTANCE = buildFromConfiguration();
 
-  private static final int DEFAULT_TIMEOUT_IN_MS = 30000;
+  public static final int DEFAULT_TIMEOUT_IN_MS = 30000;
 
-  private static final int DEFAULT_TIMEOUT_IN_SECONDS = 30;
+  public static final int DEFAULT_TIMEOUT_IN_SECONDS = 30;
 
-  private static final int DEFAULT_REQUEST_TIMEOUT_IN_MS = 30000;
+  public static final int DEFAULT_REQUEST_TIMEOUT_IN_MS = 30000;
 
-  private static final int DEFAULT_REQUEST_HEARTBEAT_TIMEOUT_IN_MS = 3000;
+  public static final int DEFAULT_REQUEST_HEARTBEAT_TIMEOUT_IN_MS = 3000;
 
-  private static final int DEFAULT_CHECK_INTERVAL_IN_S = 30;
+  public static final int DEFAULT_CHECK_INTERVAL_IN_S = 30;
 
-  private static final int DEFAULT_CHECK_TIMES = 3;
+  public static final int DEFAULT_CHECK_TIMES = 3;
 
   public static final String AUTH_ENABLED = "servicecomb.auth.enabled";
 
@@ -73,8 +55,6 @@ public final class ServiceRegistryConfig {
 
   public static final String NO_DOMAIN = "default";
 
-  private boolean ssl = true;
-
   public static final String PROXY_PRE_NAME = "servicecomb.proxy.";
 
   public static final String PROXY_ENABLE = PROXY_PRE_NAME + "enable";
@@ -101,246 +81,335 @@ public final class ServiceRegistryConfig {
 
   private String registryName = ServiceRegistry.DEFAULT_REGISTRY_NAME;
 
-  private ServiceRegistryConfig() {
+  private HttpVersion httpVersion;
+
+  private int instances;
+
+  // TODO SCB-1691 getter of this field's behavior changed, should check
+  private boolean ssl = true;
+
+  private ArrayList<IpPort> ipPort;
+
+  private int connectionTimeout;
+
+  private int idleConnectionTimeout;
+
+  private int idleWatchTimeout;
+
+  private int requestTimeout;
+
+  //Set the timeout of the heartbeat request
+  private int heartBeatRequestTimeout;
+
+  private int heartbeatInterval;
+
+  private int instancePullInterval;
+
+  private boolean registryAutoDiscovery;
+
+  private int resendHeartBeatTimes;
+
+  private boolean emptyInstanceProtectionEnabled;
+
+  private boolean alwaysOverrideSchema;
+
+  private boolean preferIpAddress;
+
+  private boolean watch;
+
+  private boolean clientAuthEnabled;
+
+  private String registryApiVersion;
+
+  private String tenantName;
+
+  private String domainName;
+
+  private String accessKey;
+
+  private String secretKey;
+
+  private boolean proxyEnable;
+
+  private String proxyHost;
+
+  private int proxyPort;
+
+  private String proxyUsername;
+
+  private String proxyPasswd;
 
+  /**
+   * Read the service registry related configurations and build the {@link ServiceRegistryConfig}
+   * object. Since most of the service registry configurations are similar, this method may be
+   * convenient to construct multiple config objects.
+   */
+  public static ServiceRegistryConfig buildFromConfiguration() {
+    return new ServiceRegistryConfigBuilder().build();
+  }
+
+  public String getTransport() {
+    return "rest";
+  }
+
+  public String getRegistryName() {
+    return registryName;
+  }
+
+  public ServiceRegistryConfig setRegistryName(String registryName) {
+    this.registryName = registryName;
+    return this;
   }
 
   public HttpVersion getHttpVersion() {
-    DynamicStringProperty property =
-        DynamicPropertyFactory.getInstance()
-            .getStringProperty("servicecomb.service.registry.client.httpVersion", "HTTP_1_1");
-    return HttpVersion.valueOf(property.get());
+    return httpVersion;
+  }
+
+  public ServiceRegistryConfig setHttpVersion(HttpVersion httpVersion) {
+    this.httpVersion = httpVersion;
+    return this;
   }
 
   public int getInstances() {
-    DynamicIntProperty property =
-        DynamicPropertyFactory.getInstance()
-            .getIntProperty(VERTICLE_INSTANCES, 1);
-    int deployInstances = property.get();
-    if (deployInstances <= 0) {
-      int nAvailableProcessors = Runtime.getRuntime().availableProcessors();
-      LOGGER.warn("The property `{}` must be positive integer, fallback to use number of available processors: {}",
-          VERTICLE_INSTANCES,
-          nAvailableProcessors);
-      return nAvailableProcessors;
-    }
-    return deployInstances;
+    return instances;
+  }
+
+  public ServiceRegistryConfig setInstances(int instances) {
+    this.instances = instances;
+    return this;
   }
 
   public boolean isSsl() {
-    getIpPort();
-    return this.ssl;
+    return ssl;
+  }
+
+  public ServiceRegistryConfig setSsl(boolean ssl) {
+    this.ssl = ssl;
+    return this;
   }
 
   public ArrayList<IpPort> getIpPort() {
-    List<String> uriList = Deployment.getSystemBootStrapInfo(DeploymentProvider.SYSTEM_KEY_SERVICE_CENTER)
-        .getAccessURL();
-    ArrayList<IpPort> ipPortList = new ArrayList<>();
-    uriList.forEach(anUriList -> {
-      try {
-        URI uri = new URI(anUriList.trim());
-        this.ssl = "https".equals(uri.getScheme());
-        ipPortList.add(NetUtils.parseIpPort(uri));
-      } catch (Exception e) {
-        LOGGER.error("servicecomb.service.registry.address invalid : {}", anUriList, e);
-      }
-    });
-    return ipPortList;
+    return ipPort;
   }
 
-  public String getTransport() {
-    return "rest";
+  public ServiceRegistryConfig setIpPort(ArrayList<IpPort> ipPort) {
+    this.ipPort = ipPort;
+    return this;
   }
 
   public int getConnectionTimeout() {
-    DynamicIntProperty property =
-        DynamicPropertyFactory.getInstance()
-            .getIntProperty("servicecomb.service.registry.client.timeout.connection", DEFAULT_TIMEOUT_IN_MS);
-    int timeout = property.get();
-    return timeout < 0 ? DEFAULT_TIMEOUT_IN_MS : timeout;
+    return connectionTimeout;
+  }
+
+  public ServiceRegistryConfig setConnectionTimeout(int connectionTimeout) {
+    this.connectionTimeout = connectionTimeout;
+    return this;
   }
 
   public int getIdleConnectionTimeout() {
-    // connection pool idle timeout based on client heart beat interval. Heart beat default value is 30.
-    DynamicIntProperty property =
-        DynamicPropertyFactory.getInstance()
-            .getIntProperty("servicecomb.service.registry.client.timeout.idle", DEFAULT_TIMEOUT_IN_SECONDS * 2);
-    int timeout = property.get();
-    return timeout < 1 ? DEFAULT_TIMEOUT_IN_SECONDS * 2 : timeout;
+    return idleConnectionTimeout;
+  }
+
+  public ServiceRegistryConfig setIdleConnectionTimeout(int idleConnectionTimeout) {
+    this.idleConnectionTimeout = idleConnectionTimeout;
+    return this;
   }
 
   public int getIdleWatchTimeout() {
-    // watch idle timeout based on SC PING/PONG interval. SC default value is 30.
-    DynamicIntProperty property =
-        DynamicPropertyFactory.getInstance()
-            .getIntProperty("servicecomb.service.registry.client.timeout.watch", DEFAULT_TIMEOUT_IN_SECONDS * 2);
-    int timeout = property.get();
-    return timeout < 1 ? DEFAULT_TIMEOUT_IN_SECONDS * 2 : timeout;
+    return idleWatchTimeout;
+  }
+
+  public ServiceRegistryConfig setIdleWatchTimeout(int idleWatchTimeout) {
+    this.idleWatchTimeout = idleWatchTimeout;
+    return this;
   }
 
   public int getRequestTimeout() {
-    DynamicIntProperty property =
-        DynamicPropertyFactory.getInstance()
-            .getIntProperty("servicecomb.service.registry.client.timeout.request", DEFAULT_REQUEST_TIMEOUT_IN_MS);
-    int timeout = property.get();
-    return timeout < 1 ? DEFAULT_REQUEST_TIMEOUT_IN_MS : timeout;
+    return requestTimeout;
+  }
+
+  public ServiceRegistryConfig setRequestTimeout(int requestTimeout) {
+    this.requestTimeout = requestTimeout;
+    return this;
   }
 
-  //Set the timeout of the heartbeat request
   public int getHeartBeatRequestTimeout() {
-    DynamicIntProperty property =
-        DynamicPropertyFactory.getInstance()
-            .getIntProperty("servicecomb.service.registry.client.timeout.heartbeat",
-                DEFAULT_REQUEST_HEARTBEAT_TIMEOUT_IN_MS);
-    int timeout = property.get();
-    return timeout < 1 ? DEFAULT_REQUEST_HEARTBEAT_TIMEOUT_IN_MS : timeout;
+    return heartBeatRequestTimeout;
+  }
+
+  public ServiceRegistryConfig setHeartBeatRequestTimeout(int heartBeatRequestTimeout) {
+    this.heartBeatRequestTimeout = heartBeatRequestTimeout;
+    return this;
   }
 
   public int getHeartbeatInterval() {
-    DynamicIntProperty property =
-        DynamicPropertyFactory.getInstance()
-            .getIntProperty("servicecomb.service.registry.instance.healthCheck.interval",
-                DEFAULT_CHECK_INTERVAL_IN_S);
-    int interval = property.get();
-    return interval < 0 ? DEFAULT_CHECK_INTERVAL_IN_S : interval;
+    return heartbeatInterval;
+  }
+
+  public ServiceRegistryConfig setHeartbeatInterval(int heartbeatInterval) {
+    this.heartbeatInterval = heartbeatInterval;
+    return this;
   }
 
   public int getInstancePullInterval() {
-    DynamicIntProperty property =
-        DynamicPropertyFactory.getInstance()
-            .getIntProperty("servicecomb.service.registry.instance.pull.interval",
-                DEFAULT_CHECK_INTERVAL_IN_S);
-    int interval = property.get();
-    return interval < 0 ? DEFAULT_CHECK_INTERVAL_IN_S : interval;
+    return instancePullInterval;
   }
 
-  public long getMsInstancePullInterval() {
-    return TimeUnit.SECONDS.toMillis(getInstancePullInterval());
+  public ServiceRegistryConfig setInstancePullInterval(int instancePullInterval) {
+    this.instancePullInterval = instancePullInterval;
+    return this;
   }
 
   public boolean isRegistryAutoDiscovery() {
-    DynamicBooleanProperty property =
-        DynamicPropertyFactory.getInstance()
-            .getBooleanProperty("servicecomb.service.registry.autodiscovery",
-                false);
-    return property.get();
+    return registryAutoDiscovery;
+  }
+
+  public ServiceRegistryConfig setRegistryAutoDiscovery(boolean registryAutoDiscovery) {
+    this.registryAutoDiscovery = registryAutoDiscovery;
+    return this;
   }
 
   public int getResendHeartBeatTimes() {
-    DynamicIntProperty property =
-        DynamicPropertyFactory.getInstance()
-            .getIntProperty("servicecomb.service.registry.instance.healthCheck.times",
-                DEFAULT_CHECK_TIMES);
-    int times = property.get();
-    return times < 0 ? DEFAULT_CHECK_TIMES : times;
+    return resendHeartBeatTimes;
+  }
+
+  public ServiceRegistryConfig setResendHeartBeatTimes(int resendHeartBeatTimes) {
+    this.resendHeartBeatTimes = resendHeartBeatTimes;
+    return this;
   }
 
   public boolean isEmptyInstanceProtectionEnabled() {
-    DynamicBooleanProperty property =
-        DynamicPropertyFactory.getInstance()
-            .getBooleanProperty("servicecomb.service.registry.instance.empty.protection",
-                true);
-    return property.get();
+    return emptyInstanceProtectionEnabled;
+  }
+
+  public ServiceRegistryConfig setEmptyInstanceProtectionEnabled(boolean emptyInstanceProtectionEnabled) {
+    this.emptyInstanceProtectionEnabled = emptyInstanceProtectionEnabled;
+    return this;
   }
 
   public boolean isAlwaysOverrideSchema() {
-    DynamicBooleanProperty property =
-        DynamicPropertyFactory.getInstance()
-            .getBooleanProperty("servicecomb.service.registry.instance.alwaysOverrideSchema",
-                false);
-    return property.get();
+    return alwaysOverrideSchema;
+  }
+
+  public ServiceRegistryConfig setAlwaysOverrideSchema(boolean alwaysOverrideSchema) {
+    this.alwaysOverrideSchema = alwaysOverrideSchema;
+    return this;
   }
 
   public boolean isPreferIpAddress() {
-    DynamicBooleanProperty property =
-        DynamicPropertyFactory.getInstance()
-            .getBooleanProperty("servicecomb.service.registry.instance.preferIpAddress",
-                false);
-    return property.get();
+    return preferIpAddress;
+  }
+
+  public ServiceRegistryConfig setPreferIpAddress(boolean preferIpAddress) {
+    this.preferIpAddress = preferIpAddress;
+    return this;
   }
 
   public boolean isWatch() {
-    DynamicBooleanProperty property =
-        DynamicPropertyFactory.getInstance()
-            .getBooleanProperty("servicecomb.service.registry.instance.watch",
-                true);
-    return property.get();
+    return watch;
+  }
+
+  public ServiceRegistryConfig setWatch(boolean watch) {
+    this.watch = watch;
+    return this;
   }
 
   public boolean isClientAuthEnabled() {
-    String isAuthEnabled = getProperty("false", AUTH_ENABLED);
-    return Boolean.parseBoolean(isAuthEnabled);
+    return clientAuthEnabled;
+  }
+
+  public ServiceRegistryConfig setClientAuthEnabled(boolean clientAuthEnabled) {
+    this.clientAuthEnabled = clientAuthEnabled;
+    return this;
   }
 
   public String getRegistryApiVersion() {
-    return getProperty("v4", REGISTRY_API_VERSION);
+    return registryApiVersion;
+  }
+
+  public ServiceRegistryConfig setRegistryApiVersion(String registryApiVersion) {
+    this.registryApiVersion = registryApiVersion;
+    return this;
   }
 
   public String getTenantName() {
-    return getProperty(NO_TENANT, TENANT_NAME);
+    return tenantName;
+  }
+
+  public ServiceRegistryConfig setTenantName(String tenantName) {
+    this.tenantName = tenantName;
+    return this;
   }
 
   public String getDomainName() {
-    return getProperty(NO_DOMAIN, DOMAIN_NAME);
+    return domainName;
+  }
+
+  public ServiceRegistryConfig setDomainName(String domainName) {
+    this.domainName = domainName;
+    return this;
   }
 
   public String getAccessKey() {
-    String tenantName = getProperty(null, TENANT_ACCESS_KEY);
-    return tenantName;
+    return accessKey;
+  }
+
+  public ServiceRegistryConfig setAccessKey(String accessKey) {
+    this.accessKey = accessKey;
+    return this;
   }
 
   public String getSecretKey() {
-    String tenantName = getProperty(null, TENANT_SECRET_KEY);
-    return tenantName;
+    return secretKey;
+  }
+
+  public ServiceRegistryConfig setSecretKey(String secretKey) {
+    this.secretKey = secretKey;
+    return this;
   }
 
   public Boolean isProxyEnable() {
-    String enable = getProperty("false", PROXY_ENABLE);
-    return Boolean.parseBoolean(enable);
+    return proxyEnable;
+  }
+
+  public ServiceRegistryConfig setProxyEnable(Boolean proxyEnable) {
+    this.proxyEnable = proxyEnable;
+    return this;
   }
 
   public String getProxyHost() {
-    String host = getProperty("127.0.0.1", PROXY_HOST);
-    return host;
+    return proxyHost;
   }
 
-  public int getProxyPort() {
-    String port = getProperty("8080", PROXY_PORT);
-    return Integer.parseInt(port);
+  public ServiceRegistryConfig setProxyHost(String proxyHost) {
+    this.proxyHost = proxyHost;
+    return this;
   }
 
-  public String getProxyUsername() {
-    String username = getProperty(null, PROXY_USERNAME);
-    return username;
+  public int getProxyPort() {
+    return proxyPort;
   }
 
-  public String getProxyPasswd() {
-    String passwd = getProperty(null, PROXY_PASSWD);
-    return passwd;
+  public ServiceRegistryConfig setProxyPort(int proxyPort) {
+    this.proxyPort = proxyPort;
+    return this;
   }
 
-  public String getRegistryName() {
-    return registryName;
+  public String getProxyUsername() {
+    return proxyUsername;
   }
 
-  public ServiceRegistryConfig setRegistryName(String registryName) {
-    this.registryName = registryName;
+  public ServiceRegistryConfig setProxyUsername(String proxyUsername) {
+    this.proxyUsername = proxyUsername;
     return this;
   }
 
-  private String getProperty(String defaultValue, String... keys) {
-    String property = null;
-    for (String key : keys) {
-      property = DynamicPropertyFactory.getInstance().getStringProperty(key, null).get();
-      if (property != null) {
-        break;
-      }
-    }
-
-    if (property != null) {
-      return property;
-    } else {
-      return defaultValue;
-    }
+  public String getProxyPasswd() {
+    return proxyPasswd;
+  }
+
+  public ServiceRegistryConfig setProxyPasswd(String proxyPasswd) {
+    this.proxyPasswd = proxyPasswd;
+    return this;
   }
 }
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfigBuilder.java
similarity index 62%
copy from service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
copy to service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfigBuilder.java
index 9d5e440..95f2b6c 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfigBuilder.java
@@ -20,13 +20,13 @@ package org.apache.servicecomb.serviceregistry.config;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.TimeUnit;
+import java.util.Objects;
 
+import org.apache.servicecomb.config.ConfigUtil;
 import org.apache.servicecomb.deployment.Deployment;
 import org.apache.servicecomb.deployment.DeploymentProvider;
 import org.apache.servicecomb.foundation.common.net.IpPort;
 import org.apache.servicecomb.foundation.common.net.NetUtils;
-import org.apache.servicecomb.serviceregistry.ServiceRegistry;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -37,72 +37,46 @@ import com.netflix.config.DynamicStringProperty;
 
 import io.vertx.core.http.HttpVersion;
 
-/**
- * Created by   on 2016/12/23.
- */
-public final class ServiceRegistryConfig {
-  private static final Logger LOGGER = LoggerFactory.getLogger(ServiceRegistryConfig.class);
-
-  public static final ServiceRegistryConfig INSTANCE = new ServiceRegistryConfig();
-
-  private static final int DEFAULT_TIMEOUT_IN_MS = 30000;
-
-  private static final int DEFAULT_TIMEOUT_IN_SECONDS = 30;
-
-  private static final int DEFAULT_REQUEST_TIMEOUT_IN_MS = 30000;
-
-  private static final int DEFAULT_REQUEST_HEARTBEAT_TIMEOUT_IN_MS = 3000;
-
-  private static final int DEFAULT_CHECK_INTERVAL_IN_S = 30;
-
-  private static final int DEFAULT_CHECK_TIMES = 3;
-
-  public static final String AUTH_ENABLED = "servicecomb.auth.enabled";
-
-  public static final String TENANT_ACCESS_KEY = "servicecomb.auth.accessKey";
-
-  public static final String TENANT_SECRET_KEY = "servicecomb.auth.secretKey";
-
-  public static final String REGISTRY_API_VERSION = "servicecomb.service.registry.api.version";
-
-  public static final String TENANT_NAME = "servicecomb.config.client.tenantName";
-
-  public static final String DOMAIN_NAME = "servicecomb.config.client.domainName";
-
-  public static final String NO_TENANT = "default";
-
-  public static final String NO_DOMAIN = "default";
-
-  private boolean ssl = true;
-
-  public static final String PROXY_PRE_NAME = "servicecomb.proxy.";
-
-  public static final String PROXY_ENABLE = PROXY_PRE_NAME + "enable";
-
-  public static final String PROXY_HOST = PROXY_PRE_NAME + "host";
-
-  public static final String PROXY_PORT = PROXY_PRE_NAME + "port";
-
-  public static final String PROXY_USERNAME = PROXY_PRE_NAME + "username";
-
-  public static final String PROXY_PASSWD = PROXY_PRE_NAME + "passwd";
-
-  public static final String SSL_KEY = "sc.consumer";
-
-  public static final String PROXY_KEY = "sc.consumer";
-
-  public static final String VERTICLE_INSTANCES = "servicecomb.service.registry.client.instances";
-
-  public static final String EVENT_LOOP_POOL_SIZE = "servicecomb.service.registry.client.eventLoopPoolSize";
-
-  public static final String WORKER_POOL_SIZE = "servicecomb.service.registry.client.workerPoolSize";
-
-  public static final String WORKER_POOL_NAME = "registry-vert.x-worker-thread";
-
-  private String registryName = ServiceRegistry.DEFAULT_REGISTRY_NAME;
-
-  private ServiceRegistryConfig() {
-
+class ServiceRegistryConfigBuilder {
+  private static final Logger LOGGER = LoggerFactory.getLogger(ServiceRegistryConfigBuilder.class);
+
+  static {
+    // ensure configurations are loaded properly
+    ConfigUtil.installDynamicConfig();
+  }
+
+  private boolean ssl;
+
+  public ServiceRegistryConfig build() {
+    return new ServiceRegistryConfig()
+        .setHttpVersion(getHttpVersion())
+        .setInstances(getInstances())
+        .setIpPort(getIpPort())
+        .setSsl(isSsl())
+        .setConnectionTimeout(getConnectionTimeout())
+        .setIdleConnectionTimeout(getIdleConnectionTimeout())
+        .setIdleWatchTimeout(getIdleWatchTimeout())
+        .setRequestTimeout(getRequestTimeout())
+        .setHeartBeatRequestTimeout(getHeartBeatRequestTimeout())
+        .setHeartbeatInterval(getHeartbeatInterval())
+        .setInstancePullInterval(getInstancePullInterval())
+        .setRegistryAutoDiscovery(isRegistryAutoDiscovery())
+        .setResendHeartBeatTimes(getResendHeartBeatTimes())
+        .setEmptyInstanceProtectionEnabled(isEmptyInstanceProtectionEnabled())
+        .setAlwaysOverrideSchema(isAlwaysOverrideSchema())
+        .setPreferIpAddress(isPreferIpAddress())
+        .setWatch(isWatch())
+        .setClientAuthEnabled(isClientAuthEnabled())
+        .setRegistryApiVersion(getRegistryApiVersion())
+        .setTenantName(getTenantName())
+        .setDomainName(getDomainName())
+        .setAccessKey(getAccessKey())
+        .setSecretKey(getSecretKey())
+        .setProxyEnable(isProxyEnable())
+        .setProxyHost(getProxyHost())
+        .setProxyPort(getProxyPort())
+        .setProxyUsername(getProxyUsername())
+        .setProxyPasswd(getProxyPasswd());
   }
 
   public HttpVersion getHttpVersion() {
@@ -115,25 +89,29 @@ public final class ServiceRegistryConfig {
   public int getInstances() {
     DynamicIntProperty property =
         DynamicPropertyFactory.getInstance()
-            .getIntProperty(VERTICLE_INSTANCES, 1);
+            .getIntProperty(ServiceRegistryConfig.VERTICLE_INSTANCES, 1);
     int deployInstances = property.get();
     if (deployInstances <= 0) {
       int nAvailableProcessors = Runtime.getRuntime().availableProcessors();
       LOGGER.warn("The property `{}` must be positive integer, fallback to use number of available processors: {}",
-          VERTICLE_INSTANCES,
+          ServiceRegistryConfig.VERTICLE_INSTANCES,
           nAvailableProcessors);
       return nAvailableProcessors;
     }
     return deployInstances;
   }
 
+  /**
+   * must be invoked after {@link #getIpPort()}
+   */
   public boolean isSsl() {
-    getIpPort();
     return this.ssl;
   }
 
   public ArrayList<IpPort> getIpPort() {
-    List<String> uriList = Deployment.getSystemBootStrapInfo(DeploymentProvider.SYSTEM_KEY_SERVICE_CENTER)
+    List<String> uriList = Objects
+        .requireNonNull(Deployment.getSystemBootStrapInfo(DeploymentProvider.SYSTEM_KEY_SERVICE_CENTER),
+            "no sc address found!")
         .getAccessURL();
     ArrayList<IpPort> ipPortList = new ArrayList<>();
     uriList.forEach(anUriList -> {
@@ -155,35 +133,39 @@ public final class ServiceRegistryConfig {
   public int getConnectionTimeout() {
     DynamicIntProperty property =
         DynamicPropertyFactory.getInstance()
-            .getIntProperty("servicecomb.service.registry.client.timeout.connection", DEFAULT_TIMEOUT_IN_MS);
+            .getIntProperty("servicecomb.service.registry.client.timeout.connection",
+                ServiceRegistryConfig.DEFAULT_TIMEOUT_IN_MS);
     int timeout = property.get();
-    return timeout < 0 ? DEFAULT_TIMEOUT_IN_MS : timeout;
+    return timeout < 0 ? ServiceRegistryConfig.DEFAULT_TIMEOUT_IN_MS : timeout;
   }
 
   public int getIdleConnectionTimeout() {
     // connection pool idle timeout based on client heart beat interval. Heart beat default value is 30.
     DynamicIntProperty property =
         DynamicPropertyFactory.getInstance()
-            .getIntProperty("servicecomb.service.registry.client.timeout.idle", DEFAULT_TIMEOUT_IN_SECONDS * 2);
+            .getIntProperty("servicecomb.service.registry.client.timeout.idle",
+                ServiceRegistryConfig.DEFAULT_TIMEOUT_IN_SECONDS * 2);
     int timeout = property.get();
-    return timeout < 1 ? DEFAULT_TIMEOUT_IN_SECONDS * 2 : timeout;
+    return timeout < 1 ? ServiceRegistryConfig.DEFAULT_TIMEOUT_IN_SECONDS * 2 : timeout;
   }
 
   public int getIdleWatchTimeout() {
     // watch idle timeout based on SC PING/PONG interval. SC default value is 30.
     DynamicIntProperty property =
         DynamicPropertyFactory.getInstance()
-            .getIntProperty("servicecomb.service.registry.client.timeout.watch", DEFAULT_TIMEOUT_IN_SECONDS * 2);
+            .getIntProperty("servicecomb.service.registry.client.timeout.watch",
+                ServiceRegistryConfig.DEFAULT_TIMEOUT_IN_SECONDS * 2);
     int timeout = property.get();
-    return timeout < 1 ? DEFAULT_TIMEOUT_IN_SECONDS * 2 : timeout;
+    return timeout < 1 ? ServiceRegistryConfig.DEFAULT_TIMEOUT_IN_SECONDS * 2 : timeout;
   }
 
   public int getRequestTimeout() {
     DynamicIntProperty property =
         DynamicPropertyFactory.getInstance()
-            .getIntProperty("servicecomb.service.registry.client.timeout.request", DEFAULT_REQUEST_TIMEOUT_IN_MS);
+            .getIntProperty("servicecomb.service.registry.client.timeout.request",
+                ServiceRegistryConfig.DEFAULT_REQUEST_TIMEOUT_IN_MS);
     int timeout = property.get();
-    return timeout < 1 ? DEFAULT_REQUEST_TIMEOUT_IN_MS : timeout;
+    return timeout < 1 ? ServiceRegistryConfig.DEFAULT_REQUEST_TIMEOUT_IN_MS : timeout;
   }
 
   //Set the timeout of the heartbeat request
@@ -191,31 +173,27 @@ public final class ServiceRegistryConfig {
     DynamicIntProperty property =
         DynamicPropertyFactory.getInstance()
             .getIntProperty("servicecomb.service.registry.client.timeout.heartbeat",
-                DEFAULT_REQUEST_HEARTBEAT_TIMEOUT_IN_MS);
+                ServiceRegistryConfig.DEFAULT_REQUEST_HEARTBEAT_TIMEOUT_IN_MS);
     int timeout = property.get();
-    return timeout < 1 ? DEFAULT_REQUEST_HEARTBEAT_TIMEOUT_IN_MS : timeout;
+    return timeout < 1 ? ServiceRegistryConfig.DEFAULT_REQUEST_HEARTBEAT_TIMEOUT_IN_MS : timeout;
   }
 
   public int getHeartbeatInterval() {
     DynamicIntProperty property =
         DynamicPropertyFactory.getInstance()
             .getIntProperty("servicecomb.service.registry.instance.healthCheck.interval",
-                DEFAULT_CHECK_INTERVAL_IN_S);
+                ServiceRegistryConfig.DEFAULT_CHECK_INTERVAL_IN_S);
     int interval = property.get();
-    return interval < 0 ? DEFAULT_CHECK_INTERVAL_IN_S : interval;
+    return interval < 0 ? ServiceRegistryConfig.DEFAULT_CHECK_INTERVAL_IN_S : interval;
   }
 
   public int getInstancePullInterval() {
     DynamicIntProperty property =
         DynamicPropertyFactory.getInstance()
             .getIntProperty("servicecomb.service.registry.instance.pull.interval",
-                DEFAULT_CHECK_INTERVAL_IN_S);
+                ServiceRegistryConfig.DEFAULT_CHECK_INTERVAL_IN_S);
     int interval = property.get();
-    return interval < 0 ? DEFAULT_CHECK_INTERVAL_IN_S : interval;
-  }
-
-  public long getMsInstancePullInterval() {
-    return TimeUnit.SECONDS.toMillis(getInstancePullInterval());
+    return interval < 0 ? ServiceRegistryConfig.DEFAULT_CHECK_INTERVAL_IN_S : interval;
   }
 
   public boolean isRegistryAutoDiscovery() {
@@ -230,9 +208,9 @@ public final class ServiceRegistryConfig {
     DynamicIntProperty property =
         DynamicPropertyFactory.getInstance()
             .getIntProperty("servicecomb.service.registry.instance.healthCheck.times",
-                DEFAULT_CHECK_TIMES);
+                ServiceRegistryConfig.DEFAULT_CHECK_TIMES);
     int times = property.get();
-    return times < 0 ? DEFAULT_CHECK_TIMES : times;
+    return times < 0 ? ServiceRegistryConfig.DEFAULT_CHECK_TIMES : times;
   }
 
   public boolean isEmptyInstanceProtectionEnabled() {
@@ -268,64 +246,50 @@ public final class ServiceRegistryConfig {
   }
 
   public boolean isClientAuthEnabled() {
-    String isAuthEnabled = getProperty("false", AUTH_ENABLED);
+    String isAuthEnabled = getProperty("false", ServiceRegistryConfig.AUTH_ENABLED);
     return Boolean.parseBoolean(isAuthEnabled);
   }
 
   public String getRegistryApiVersion() {
-    return getProperty("v4", REGISTRY_API_VERSION);
+    return getProperty("v4", ServiceRegistryConfig.REGISTRY_API_VERSION);
   }
 
   public String getTenantName() {
-    return getProperty(NO_TENANT, TENANT_NAME);
+    return getProperty(ServiceRegistryConfig.NO_TENANT, ServiceRegistryConfig.TENANT_NAME);
   }
 
   public String getDomainName() {
-    return getProperty(NO_DOMAIN, DOMAIN_NAME);
+    return getProperty(ServiceRegistryConfig.NO_DOMAIN, ServiceRegistryConfig.DOMAIN_NAME);
   }
 
   public String getAccessKey() {
-    String tenantName = getProperty(null, TENANT_ACCESS_KEY);
-    return tenantName;
+    return getProperty(null, ServiceRegistryConfig.TENANT_ACCESS_KEY);
   }
 
   public String getSecretKey() {
-    String tenantName = getProperty(null, TENANT_SECRET_KEY);
-    return tenantName;
+    return getProperty(null, ServiceRegistryConfig.TENANT_SECRET_KEY);
   }
 
   public Boolean isProxyEnable() {
-    String enable = getProperty("false", PROXY_ENABLE);
+    String enable = getProperty("false", ServiceRegistryConfig.PROXY_ENABLE);
     return Boolean.parseBoolean(enable);
   }
 
   public String getProxyHost() {
-    String host = getProperty("127.0.0.1", PROXY_HOST);
-    return host;
+    return getProperty("127.0.0.1", ServiceRegistryConfig.PROXY_HOST);
   }
 
   public int getProxyPort() {
-    String port = getProperty("8080", PROXY_PORT);
+    String port = getProperty("8080", ServiceRegistryConfig.PROXY_PORT);
     return Integer.parseInt(port);
   }
 
   public String getProxyUsername() {
-    String username = getProperty(null, PROXY_USERNAME);
-    return username;
+    return getProperty(null, ServiceRegistryConfig.PROXY_USERNAME);
   }
 
   public String getProxyPasswd() {
-    String passwd = getProperty(null, PROXY_PASSWD);
-    return passwd;
-  }
-
-  public String getRegistryName() {
-    return registryName;
-  }
-
-  public ServiceRegistryConfig setRegistryName(String registryName) {
-    this.registryName = registryName;
-    return this;
+    return getProperty(null, ServiceRegistryConfig.PROXY_PASSWD);
   }
 
   private String getProperty(String defaultValue, String... keys) {
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestServiceRegistryConfig.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestServiceRegistryConfig.java
index fc3be5a..f26d337 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestServiceRegistryConfig.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/config/TestServiceRegistryConfig.java
@@ -43,7 +43,7 @@ public class TestServiceRegistryConfig {
 
   @Test
   public void testServiceRegistryConfig() {
-    ServiceRegistryConfig oConfig = ServiceRegistryConfig.INSTANCE;
+    ServiceRegistryConfig oConfig = new ServiceRegistryConfigBuilder().build();
     Assert.assertNull(oConfig.getAccessKey());
     Assert.assertEquals(30000, oConfig.getConnectionTimeout());
     Assert.assertNotEquals(null, oConfig.getHeartbeatInterval());
@@ -62,10 +62,10 @@ public class TestServiceRegistryConfig {
     List<IpPort> ipPorts = oConfig.getIpPort();
     Assert.assertEquals("127.0.0.1:80", ipPorts.get(0).toString());
     Assert.assertEquals("127.0.0.1:443", ipPorts.get(1).toString());
-    Assert.assertFalse(ServiceRegistryConfig.INSTANCE.isProxyEnable());
-    Assert.assertEquals("127.0.0.1", ServiceRegistryConfig.INSTANCE.getProxyHost());
-    Assert.assertEquals(8080, ServiceRegistryConfig.INSTANCE.getProxyPort());
-    Assert.assertNull(ServiceRegistryConfig.INSTANCE.getProxyUsername());
-    Assert.assertNull(ServiceRegistryConfig.INSTANCE.getProxyPasswd());
+    Assert.assertFalse(oConfig.isProxyEnable());
+    Assert.assertEquals("127.0.0.1", oConfig.getProxyHost());
+    Assert.assertEquals(8080, oConfig.getProxyPort());
+    Assert.assertNull(oConfig.getProxyUsername());
+    Assert.assertNull(oConfig.getProxyPasswd());
   }
 }


[servicecomb-java-chassis] 16/19: [SCB-1691] support multiple TLS enabled sc clusters

Posted by ya...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

yaohaishi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit bbd7702fbee7df950ef43d703f604f4b3fc90140
Author: yhs0092 <yh...@163.com>
AuthorDate: Mon Feb 17 09:19:31 2020 +0800

    [SCB-1691] support multiple TLS enabled sc clusters
    
    - RemoteServiceRegistry create ServiceRegistryClient by the constructor in ServiceRegistryConfig
    - AbstractClientPool accept ServiceRegistryConfig in constructor
    - Allow to specify registry client TLS and proxy config by custom tags
---
 .../client/http/AbstractClientPool.java            | 12 +++++--
 .../client/http/HttpClientPool.java                | 13 +++----
 .../client/http/WebsocketClientPool.java           | 11 +++---
 .../config/ServiceRegistryConfig.java              | 41 ++++++++++++++++++++++
 .../registry/RemoteServiceRegistry.java            |  3 +-
 .../client/http/TestHttpClientPool.java            | 24 ++++++++++---
 .../client/http/TestWebsocketClientPool.java       | 12 +++++--
 7 files changed, 94 insertions(+), 22 deletions(-)

diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/AbstractClientPool.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/AbstractClientPool.java
index 968d858..c709692 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/AbstractClientPool.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/AbstractClientPool.java
@@ -41,17 +41,23 @@ import io.vertx.core.http.HttpClientOptions;
 abstract class AbstractClientPool implements ClientPool {
   private static final Logger LOGGER = LoggerFactory.getLogger(AbstractClientPool.class);
 
+  private ServiceRegistryConfig serviceRegistryConfig;
+
   private HttpClientOptions httpClientOptions;
 
   private ClientPoolManager<HttpClientWithContext> clientMgr;
 
-  AbstractClientPool(HttpClientOptions httpClientOptions) {
-    this.httpClientOptions = httpClientOptions;
+  AbstractClientPool(ServiceRegistryConfig serviceRegistryConfig) {
+    this.serviceRegistryConfig = serviceRegistryConfig;
+    this.httpClientOptions = getHttpClientOptionsFromConfigurations(serviceRegistryConfig);
     create();
   }
 
   protected abstract boolean isWorker();
 
+  protected abstract HttpClientOptions getHttpClientOptionsFromConfigurations(
+      ServiceRegistryConfig serviceRegistryConfig);
+
   public HttpClientWithContext getClient() {
     return this.clientMgr.findThreadBindClientPool();
   }
@@ -64,7 +70,7 @@ abstract class AbstractClientPool implements ClientPool {
 
     // 这里面是同步接口,且好像直接在事件线程中用,保险起见,先使用独立的vertx实例
     VertxOptions vertxOptions = new VertxOptions()
-        .setAddressResolverOptions(AddressResolverConfig.getAddressResover(ServiceRegistryConfig.SSL_KEY))
+        .setAddressResolverOptions(AddressResolverConfig.getAddressResover(serviceRegistryConfig.getSslConfigTag()))
         .setEventLoopPoolSize(property.get());
     Vertx vertx = VertxUtils.getOrCreateVertxByName("registry", vertxOptions);
     clientMgr = new ClientPoolManager<>(vertx, new HttpClientPoolFactory(httpClientOptions));
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/HttpClientPool.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/HttpClientPool.java
index f4d28c8..962a81c 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/HttpClientPool.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/HttpClientPool.java
@@ -27,7 +27,7 @@ import io.vertx.core.http.HttpClientOptions;
 import io.vertx.core.http.HttpVersion;
 import io.vertx.core.net.ProxyOptions;
 
-final class HttpClientPool extends AbstractClientPool {
+class HttpClientPool extends AbstractClientPool {
 
   private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientPool.class);
 
@@ -37,11 +37,11 @@ final class HttpClientPool extends AbstractClientPool {
   public static final HttpClientPool INSTANCE = new HttpClientPool();
 
   private HttpClientPool() {
-    super(getHttpClientOptionsFromConfigurations(ServiceRegistryConfig.INSTANCE));
+    super(ServiceRegistryConfig.INSTANCE);
   }
 
   HttpClientPool(ServiceRegistryConfig serviceRegistryConfig) {
-    super(getHttpClientOptionsFromConfigurations(serviceRegistryConfig));
+    super(serviceRegistryConfig);
   }
 
   @Override
@@ -49,7 +49,8 @@ final class HttpClientPool extends AbstractClientPool {
     return false;
   }
 
-  static HttpClientOptions getHttpClientOptionsFromConfigurations(ServiceRegistryConfig serviceRegistryConfig) {
+  @Override
+  protected HttpClientOptions getHttpClientOptionsFromConfigurations(ServiceRegistryConfig serviceRegistryConfig) {
     HttpVersion ver = serviceRegistryConfig.getHttpVersion();
     HttpClientOptions httpClientOptions = new HttpClientOptions();
     httpClientOptions.setProtocolVersion(ver);
@@ -61,7 +62,7 @@ final class HttpClientPool extends AbstractClientPool {
       proxy.setPort(serviceRegistryConfig.getProxyPort());
       proxy.setUsername(serviceRegistryConfig.getProxyUsername());
       proxy.setPassword(
-          Encryptions.decode(serviceRegistryConfig.getProxyPasswd(), ServiceRegistryConfig.PROXY_KEY));
+          Encryptions.decode(serviceRegistryConfig.getProxyPasswd(), serviceRegistryConfig.getProxyConfigTag()));
       httpClientOptions.setProxyOptions(proxy);
     }
     if (ver == HttpVersion.HTTP_2) {
@@ -70,7 +71,7 @@ final class HttpClientPool extends AbstractClientPool {
     }
     if (serviceRegistryConfig.isSsl()) {
       LOGGER.debug("service center client performs requests over TLS");
-      VertxTLSBuilder.buildHttpClientOptions(ServiceRegistryConfig.SSL_KEY, httpClientOptions);
+      VertxTLSBuilder.buildHttpClientOptions(serviceRegistryConfig.getSslConfigTag(), httpClientOptions);
     }
     return httpClientOptions;
   }
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientPool.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientPool.java
index 38c17be..96ab64f 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientPool.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientPool.java
@@ -25,7 +25,7 @@ import org.slf4j.LoggerFactory;
 import io.vertx.core.http.HttpClientOptions;
 import io.vertx.core.http.HttpVersion;
 
-public final class WebsocketClientPool extends AbstractClientPool {
+public class WebsocketClientPool extends AbstractClientPool {
 
   private static final Logger LOGGER = LoggerFactory.getLogger(WebsocketClientPool.class);
 
@@ -35,11 +35,11 @@ public final class WebsocketClientPool extends AbstractClientPool {
   public static final WebsocketClientPool INSTANCE = new WebsocketClientPool();
 
   private WebsocketClientPool() {
-    super(getHttpClientOptionsFromConfigurations(ServiceRegistryConfig.INSTANCE));
+    super(ServiceRegistryConfig.INSTANCE);
   }
 
   WebsocketClientPool(ServiceRegistryConfig serviceRegistryConfig) {
-    super(getHttpClientOptionsFromConfigurations(serviceRegistryConfig));
+    super(serviceRegistryConfig);
   }
 
   @Override
@@ -47,7 +47,8 @@ public final class WebsocketClientPool extends AbstractClientPool {
     return true;
   }
 
-  static HttpClientOptions getHttpClientOptionsFromConfigurations(ServiceRegistryConfig serviceRegistryConfig) {
+  @Override
+  protected HttpClientOptions getHttpClientOptionsFromConfigurations(ServiceRegistryConfig serviceRegistryConfig) {
     HttpVersion ver = serviceRegistryConfig.getHttpVersion();
     HttpClientOptions httpClientOptions = new HttpClientOptions();
     httpClientOptions.setProtocolVersion(ver);
@@ -59,7 +60,7 @@ public final class WebsocketClientPool extends AbstractClientPool {
     }
     if (serviceRegistryConfig.isSsl()) {
       LOGGER.debug("service center ws client performs requests over TLS");
-      VertxTLSBuilder.buildHttpClientOptions(ServiceRegistryConfig.SSL_KEY, httpClientOptions);
+      VertxTLSBuilder.buildHttpClientOptions(serviceRegistryConfig.getSslConfigTag(), httpClientOptions);
     }
     return httpClientOptions;
   }
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
index d16d485..af1e5d7 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
@@ -19,10 +19,13 @@ package org.apache.servicecomb.serviceregistry.config;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Function;
 
 import org.apache.servicecomb.foundation.auth.AuthHeaderProvider;
 import org.apache.servicecomb.foundation.common.net.IpPort;
 import org.apache.servicecomb.serviceregistry.ServiceRegistry;
+import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient;
+import org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl;
 
 import io.vertx.core.http.HttpVersion;
 
@@ -141,8 +144,18 @@ public final class ServiceRegistryConfig {
 
   private String proxyPasswd;
 
+  private String sslConfigTag = SSL_KEY;
+
+  private String proxyConfigTag = PROXY_KEY;
+
   private List<AuthHeaderProvider> authHeaderProviders;
 
+  private Function<ServiceRegistry, ServiceRegistryClient> serviceRegistryClientConstructor =
+      serviceRegistry -> new ServiceRegistryClientImpl(this);
+
+  public ServiceRegistryConfig() {
+  }
+
   /**
    * Read the service registry related configurations and build the {@link ServiceRegistryConfig}
    * object. Since most of the service registry configurations are similar, this method may be
@@ -417,6 +430,24 @@ public final class ServiceRegistryConfig {
     return this;
   }
 
+  public String getSslConfigTag() {
+    return sslConfigTag;
+  }
+
+  public ServiceRegistryConfig setSslConfigTag(String sslConfigTag) {
+    this.sslConfigTag = sslConfigTag;
+    return this;
+  }
+
+  public String getProxyConfigTag() {
+    return proxyConfigTag;
+  }
+
+  public ServiceRegistryConfig setProxyConfigTag(String proxyConfigTag) {
+    this.proxyConfigTag = proxyConfigTag;
+    return this;
+  }
+
   public List<AuthHeaderProvider> getAuthHeaderProviders() {
     return authHeaderProviders;
   }
@@ -426,4 +457,14 @@ public final class ServiceRegistryConfig {
     this.authHeaderProviders = authHeaderProviders;
     return this;
   }
+
+  public ServiceRegistryConfig setServiceRegistryClientConstructor(
+      Function<ServiceRegistry, ServiceRegistryClient> serviceRegistryClientConstructor) {
+    this.serviceRegistryClientConstructor = serviceRegistryClientConstructor;
+    return this;
+  }
+
+  public ServiceRegistryClient createServiceRegistryClient(ServiceRegistry serviceRegistry) {
+    return this.serviceRegistryClientConstructor.apply(serviceRegistry);
+  }
 }
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java
index a53e4ac..d68a46e 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java
@@ -24,7 +24,6 @@ import java.util.concurrent.TimeUnit;
 import org.apache.servicecomb.foundation.common.concurrency.SuppressedRunnableWrapper;
 import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
 import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient;
-import org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl;
 import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
 import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition;
 import org.slf4j.Logger;
@@ -68,7 +67,7 @@ public class RemoteServiceRegistry extends AbstractServiceRegistry {
 
   @Override
   protected ServiceRegistryClient createServiceRegistryClient() {
-    return new ServiceRegistryClientImpl(serviceRegistryConfig);
+    return serviceRegistryConfig.createServiceRegistryClient(this);
   }
 
   @Override
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestHttpClientPool.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestHttpClientPool.java
index ba74331..4b57d61 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestHttpClientPool.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestHttpClientPool.java
@@ -46,7 +46,11 @@ public class TestHttpClientPool {
     ArchaiusUtils.setProperty(ServiceRegistryConfig.PROXY_USERNAME, "user");
     ArchaiusUtils.setProperty(ServiceRegistryConfig.PROXY_PASSWD, "pass");
 
-    HttpClientOptions httpClientOptions = HttpClientPool.getHttpClientOptionsFromConfigurations(
+    HttpClientOptions httpClientOptions = new HttpClientPool(ServiceRegistryConfig.buildFromConfiguration()) {
+      @Override
+      public void create() {
+      }
+    }.getHttpClientOptionsFromConfigurations(
         ServiceRegistryConfig.buildFromConfiguration());
 
     Assert.assertEquals(
@@ -64,7 +68,11 @@ public class TestHttpClientPool {
   public void createHttpClientOptions_noProxy() {
     ArchaiusUtils.setProperty(ServiceRegistryConfig.PROXY_ENABLE, "false");
 
-    HttpClientOptions httpClientOptions = HttpClientPool.getHttpClientOptionsFromConfigurations(
+    HttpClientOptions httpClientOptions = new HttpClientPool(ServiceRegistryConfig.buildFromConfiguration()) {
+      @Override
+      public void create() {
+      }
+    }.getHttpClientOptionsFromConfigurations(
         ServiceRegistryConfig.buildFromConfiguration());
 
     Assert.assertNull(httpClientOptions.getProxyOptions());
@@ -74,7 +82,11 @@ public class TestHttpClientPool {
   public void createHttpClientOptions_http2() {
     ArchaiusUtils.setProperty("servicecomb.service.registry.client.httpVersion", HttpVersion.HTTP_2.name());
 
-    HttpClientOptions httpClientOptions = HttpClientPool.getHttpClientOptionsFromConfigurations(
+    HttpClientOptions httpClientOptions = new HttpClientPool(ServiceRegistryConfig.buildFromConfiguration()) {
+      @Override
+      public void create() {
+      }
+    }.getHttpClientOptionsFromConfigurations(
         ServiceRegistryConfig.buildFromConfiguration());
 
     Assert.assertEquals(HttpVersion.HTTP_2, httpClientOptions.getProtocolVersion());
@@ -83,7 +95,11 @@ public class TestHttpClientPool {
 
   @Test
   public void createHttpClientOptions_notHttp2() {
-    HttpClientOptions httpClientOptions = HttpClientPool.getHttpClientOptionsFromConfigurations(
+    HttpClientOptions httpClientOptions = new HttpClientPool(ServiceRegistryConfig.buildFromConfiguration()) {
+      @Override
+      public void create() {
+      }
+    }.getHttpClientOptionsFromConfigurations(
         ServiceRegistryConfig.buildFromConfiguration());
 
     Assert.assertEquals(HttpVersion.HTTP_1_1, httpClientOptions.getProtocolVersion());
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestWebsocketClientPool.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestWebsocketClientPool.java
index 9ac4039..93c0453 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestWebsocketClientPool.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestWebsocketClientPool.java
@@ -41,7 +41,11 @@ public class TestWebsocketClientPool {
   public void createHttpClientOptions_http2() {
     ArchaiusUtils.setProperty("servicecomb.service.registry.client.httpVersion", HttpVersion.HTTP_2.name());
 
-    HttpClientOptions httpClientOptions = WebsocketClientPool.getHttpClientOptionsFromConfigurations(
+    HttpClientOptions httpClientOptions = new WebsocketClientPool(ServiceRegistryConfig.buildFromConfiguration()) {
+      @Override
+      public void create() {
+      }
+    }.getHttpClientOptionsFromConfigurations(
         ServiceRegistryConfig.buildFromConfiguration());
 
     Assert.assertEquals(HttpVersion.HTTP_2, httpClientOptions.getProtocolVersion());
@@ -50,7 +54,11 @@ public class TestWebsocketClientPool {
 
   @Test
   public void createHttpClientOptions_notHttp2() {
-    HttpClientOptions httpClientOptions = WebsocketClientPool.getHttpClientOptionsFromConfigurations(
+    HttpClientOptions httpClientOptions = new WebsocketClientPool(ServiceRegistryConfig.buildFromConfiguration()) {
+      @Override
+      public void create() {
+      }
+    }.getHttpClientOptionsFromConfigurations(
         ServiceRegistryConfig.buildFromConfiguration());
 
     Assert.assertEquals(HttpVersion.HTTP_1_1, httpClientOptions.getProtocolVersion());


[servicecomb-java-chassis] 18/19: [SCB-1691] fix CI error

Posted by ya...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

yaohaishi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit 369c57827da9969ce93af2f03340c2ac6cdda4f6
Author: yhs0092 <yh...@163.com>
AuthorDate: Sat Feb 29 03:11:57 2020 +0800

    [SCB-1691] fix CI error
---
 .../client/http/TestServiceRegistryClientImpl.java           | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java
index a63b7bc..61c179d 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java
@@ -43,7 +43,6 @@ import org.apache.servicecomb.serviceregistry.api.response.GetSchemaResponse;
 import org.apache.servicecomb.serviceregistry.api.response.GetSchemasResponse;
 import org.apache.servicecomb.serviceregistry.api.response.GetServiceResponse;
 import org.apache.servicecomb.serviceregistry.client.ClientException;
-import org.apache.servicecomb.serviceregistry.client.IpPortManager;
 import org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl.ResponseWrapper;
 import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
 import org.apache.servicecomb.serviceregistry.definition.DefinitionConst;
@@ -69,9 +68,6 @@ import mockit.MockUp;
 import mockit.Mocked;
 
 public class TestServiceRegistryClientImpl {
-  @Mocked
-  private IpPortManager ipPortManager;
-
   private ServiceRegistryClientImpl oClient = null;
 
   private Microservice microservice = new Microservice();
@@ -161,6 +157,14 @@ public class TestServiceRegistryClientImpl {
 
   @Test
   public void testRegisterSchemaNoResponse() {
+    new MockUp<RestClientUtil>() {
+      @Mock
+      void put(IpPort ipPort, String uri, RequestParam requestParam,
+          Handler<RestResponse> responseHandler) {
+        // do nothing to mock null response
+      }
+    };
+
     new RegisterSchemaTester() {
       void doRun(java.util.List<LoggingEvent> events) {
         oClient.registerSchema("msid", "schemaId", "content");


[servicecomb-java-chassis] 01/19: [SCB-1691] modify instance status change interface

Posted by ya...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

yaohaishi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit 0b507b459e0a512e74e368e19063a3c23196b16e
Author: yhs0092 <yh...@163.com>
AuthorDate: Sat Dec 28 17:51:43 2019 +0800

    [SCB-1691] modify instance status change interface
---
 .../client/LocalServiceRegistryClientImpl.java     |  30 +++---
 .../client/ServiceRegistryClient.java              |  23 ++++-
 .../client/http/ServiceRegistryClientImpl.java     |  34 +++----
 .../client/LocalServiceRegistryClientImplTest.java |  66 ++++++++++++++
 .../client/http/TestServiceRegistryClientImpl.java | 101 ++++++++++++++++-----
 5 files changed, 199 insertions(+), 55 deletions(-)

diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImpl.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImpl.java
index 4b1b6a6..cf8963f 100755
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImpl.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImpl.java
@@ -434,30 +434,26 @@ public class LocalServiceRegistryClientImpl implements ServiceRegistryClient {
   }
 
   @Override
-  public boolean undateMicroserviceInstanceStatus(String microserviceId, String microserviceInstanceId, String status) {
+  public boolean updateMicroserviceInstanceStatus(String microserviceId, String instanceId,
+      MicroserviceInstanceStatus status) {
+    if (null == status) {
+      throw new IllegalArgumentException("null status is now allowed");
+    }
+
     Map<String, MicroserviceInstance> instanceMap = microserviceInstanceMap.get(microserviceId);
     if (instanceMap == null) {
       throw new IllegalArgumentException("Invalid serviceId, serviceId=" + microserviceId);
     }
 
-    MicroserviceInstance microserviceInstance = instanceMap.get(microserviceInstanceId);
+    MicroserviceInstance microserviceInstance = instanceMap.get(instanceId);
     if (microserviceInstance == null) {
       throw new IllegalArgumentException(
-              String.format("Invalid argument. microserviceId=%s, microserviceInstanceId=%s.",
-                      microserviceId,
-                      microserviceInstanceId));
-    }
-    MicroserviceInstanceStatus instanceStatus;
-    try {
-      instanceStatus = MicroserviceInstanceStatus.valueOf(status);
-    }
-    catch (IllegalArgumentException e){
-      throw new IllegalArgumentException("Invalid status.");
-    }
-    if (null != instanceStatus) {
-      microserviceInstance.setStatus(instanceStatus);
-      return true;
+          String.format("Invalid argument. microserviceId=%s, instanceId=%s.",
+              microserviceId,
+              instanceId));
     }
-    return false;
+
+    microserviceInstance.setStatus(status);
+    return true;
   }
 }
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/ServiceRegistryClient.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/ServiceRegistryClient.java
index 81f61bf..b093c0c 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/ServiceRegistryClient.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/ServiceRegistryClient.java
@@ -179,6 +179,27 @@ public interface ServiceRegistryClient {
    * @param microserviceId
    * @param microserviceInstanceId
    * @return
+   * @deprecated use {@link #updateMicroserviceInstanceStatus(String, String, MicroserviceInstanceStatus)} instead
    */
-  boolean undateMicroserviceInstanceStatus(String microserviceId, String microserviceInstanceId, String status);
+  @Deprecated
+  default boolean undateMicroserviceInstanceStatus(String microserviceId, String microserviceInstanceId,
+      String status) {
+    MicroserviceInstanceStatus instanceStatus;
+    try {
+      instanceStatus = MicroserviceInstanceStatus.valueOf(status);
+    } catch (IllegalArgumentException e) {
+      throw new IllegalArgumentException("Invalid status: " + status);
+    }
+
+    return updateMicroserviceInstanceStatus(microserviceId, microserviceInstanceId, instanceStatus);
+  }
+
+  /**
+   * Update the instance status registered in service center.
+   * @param microserviceId the microserviceId of the instance
+   * @param instanceId the instanceId of the instance
+   * @param status update to this status
+   * @return whether this operation success
+   */
+  boolean updateMicroserviceInstanceStatus(String microserviceId, String instanceId, MicroserviceInstanceStatus status);
 }
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java
index 3c5930f..ed2e369 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java
@@ -39,6 +39,7 @@ import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.api.Const;
 import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstanceStatus;
 import org.apache.servicecomb.serviceregistry.api.registry.ServiceCenterInfo;
 import org.apache.servicecomb.serviceregistry.api.request.CreateSchemaRequest;
 import org.apache.servicecomb.serviceregistry.api.request.CreateServiceRequest;
@@ -62,7 +63,6 @@ import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient;
 import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.util.StringUtils;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.cache.CacheBuilder;
@@ -78,7 +78,9 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
   private static final Logger LOGGER = LoggerFactory.getLogger(ServiceRegistryClientImpl.class);
 
   private static final String ERROR_CODE = "errorCode";
+
   private static final String ERR_SERVICE_NOT_EXISTS = "400012";
+
   private static final String ERR_SCHEMA_NOT_EXISTS = "400016";
 
   private IpPortManager ipPortManager;
@@ -691,7 +693,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
                 callback);
             onClose.success(null);
           }, bodyBuffer -> {
-            MicroserviceInstanceChangedEvent response = null;
+            MicroserviceInstanceChangedEvent response;
             try {
               response = JsonUtils.readValue(bodyBuffer.getBytes(),
                   MicroserviceInstanceChangedEvent.class);
@@ -904,22 +906,22 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
   }
 
   @Override
-  public boolean undateMicroserviceInstanceStatus(String microserviceId, String microserviceInstanceId, String status) {
+  public boolean updateMicroserviceInstanceStatus(String microserviceId, String instanceId,
+      MicroserviceInstanceStatus status) {
+    if (null == status) {
+      throw new IllegalArgumentException("null status is now allowed");
+    }
+
     Holder<HttpClientResponse> holder = new Holder<>();
     IpPort ipPort = ipPortManager.getAvailableAddress();
     try {
-      if (LOGGER.isDebugEnabled()) {
-        LOGGER.debug("update status of microservice instance: {}", status);
-      }
-      String url = String.format(Const.REGISTRY_API.MICROSERVICE_INSTANCE_STATUS, microserviceId, microserviceInstanceId);
-      if (StringUtils.isEmpty(status)) {
-        LOGGER.debug("empty status");
-        return false;
-      }
+      LOGGER.debug("update status of microservice instance: {}", status);
+      String url = String.format(Const.REGISTRY_API.MICROSERVICE_INSTANCE_STATUS, microserviceId, instanceId);
       Map<String, String[]> queryParams = new HashMap<>();
-      queryParams.put("value", new String[] {status});
+      queryParams.put("value", new String[] {status.toString()});
       CountDownLatch countDownLatch = new CountDownLatch(1);
-      RestUtils.put(ipPort, url, new RequestParam().setQueryParams(queryParams), syncHandler(countDownLatch, HttpClientResponse.class, holder));
+      RestUtils.put(ipPort, url, new RequestParam().setQueryParams(queryParams),
+          syncHandler(countDownLatch, HttpClientResponse.class, holder));
       countDownLatch.await();
       if (holder.value != null) {
         if (holder.value.statusCode() == Status.OK.getStatusCode()) {
@@ -929,9 +931,9 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
       }
     } catch (Exception e) {
       LOGGER.error("update status of microservice instance {}/{} failed",
-              microserviceId,
-              microserviceInstanceId,
-              e);
+          microserviceId,
+          instanceId,
+          e);
     }
     return false;
   }
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java
index a1f0f03..375f299 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java
@@ -17,11 +17,14 @@
 
 package org.apache.servicecomb.serviceregistry.client;
 
+import static org.junit.Assert.fail;
+
 import java.io.InputStream;
 import java.util.List;
 
 import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstanceStatus;
 import org.apache.servicecomb.serviceregistry.api.registry.ServiceCenterInfo;
 import org.apache.servicecomb.serviceregistry.api.response.GetSchemaResponse;
 import org.apache.servicecomb.serviceregistry.client.http.Holder;
@@ -196,5 +199,68 @@ public class LocalServiceRegistryClientImplTest {
     Assert.assertThat(microservice.getSchemas().size(), Is.is(1));
     Assert.assertTrue(microservice.getSchemas().contains("hello"));
   }
+
+  @SuppressWarnings("deprecation")
+  @Test
+  public void undateMicroserviceInstanceStatus() {
+    List<MicroserviceInstance> m = registryClient
+        .findServiceInstance("", "default", "ms2", DefinitionConst.VERSION_RULE_ALL);
+    MicroserviceInstance instance = m.get(0);
+    Assert.assertEquals(MicroserviceInstanceStatus.UP, instance.getStatus());
+
+    boolean updateOperationResult = registryClient
+        .undateMicroserviceInstanceStatus(instance.getServiceId(), instance.getInstanceId(), "TESTING");
+    Assert.assertTrue(updateOperationResult);
+
+    m = registryClient
+        .findServiceInstance("", "default", "ms2", DefinitionConst.VERSION_RULE_ALL);
+    instance = m.get(0);
+    Assert.assertEquals(MicroserviceInstanceStatus.TESTING, instance.getStatus());
+  }
+
+  @SuppressWarnings("deprecation")
+  @Test
+  public void undateMicroserviceInstanceStatus_instance_not_found() {
+    try {
+      registryClient.undateMicroserviceInstanceStatus("msIdNotExist", "", "UP");
+      shouldThrowException();
+    } catch (IllegalArgumentException e) {
+      Assert.assertEquals("Invalid serviceId, serviceId=msIdNotExist", e.getMessage());
+    }
+
+    try {
+      registryClient.undateMicroserviceInstanceStatus("002", "instanceIdNotExist", "UP");
+      shouldThrowException();
+    } catch (IllegalArgumentException e) {
+      Assert.assertEquals("Invalid argument. microserviceId=002, instanceId=instanceIdNotExist.",
+          e.getMessage());
+    }
+  }
+
+  @SuppressWarnings("deprecation")
+  @Test
+  public void undateMicroserviceInstanceStatus_illegal_status() {
+    List<MicroserviceInstance> m = registryClient
+        .findServiceInstance("", "default", "ms2", DefinitionConst.VERSION_RULE_ALL);
+    MicroserviceInstance instance = m.get(0);
+
+    try {
+      registryClient.undateMicroserviceInstanceStatus(instance.getServiceId(), instance.getInstanceId(), null);
+      shouldThrowException();
+    } catch (NullPointerException e) {
+      Assert.assertEquals("Name is null", e.getMessage());
+    }
+    try {
+      registryClient
+          .undateMicroserviceInstanceStatus(instance.getServiceId(), instance.getInstanceId(), "IllegalStatus");
+      shouldThrowException();
+    } catch (IllegalArgumentException e) {
+      Assert.assertEquals("Invalid status: IllegalStatus", e.getMessage());
+    }
+  }
+
+  private void shouldThrowException() {
+    fail("an exception is expected");
+  }
 }
 
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java
index d1c855b..3a7662b 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java
@@ -18,6 +18,7 @@
 package org.apache.servicecomb.serviceregistry.client.http;
 
 import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.fail;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -124,25 +125,21 @@ public class TestServiceRegistryClientImpl {
   public void testException() {
     MicroserviceFactory microserviceFactory = new MicroserviceFactory();
     Microservice microservice = microserviceFactory.create("app", "ms");
-    Assert.assertEquals(null, oClient.registerMicroservice(microservice));
-    Assert.assertEquals(null, oClient.registerMicroserviceInstance(microservice.getInstance()));
+    Assert.assertNull(oClient.registerMicroservice(microservice));
+    Assert.assertNull(oClient.registerMicroserviceInstance(microservice.getInstance()));
     oClient.init();
-    Assert.assertEquals(null,
-        oClient.getMicroserviceId(microservice.getAppId(),
-            microservice.getServiceName(),
-            microservice.getVersion(),
-            microservice.getEnvironment()));
+    Assert.assertNull(oClient.getMicroserviceId(microservice.getAppId(),
+        microservice.getServiceName(),
+        microservice.getVersion(),
+        microservice.getEnvironment()));
     Assert.assertThat(oClient.getAllMicroservices().isEmpty(), is(true));
-    Assert.assertEquals(null, oClient.registerMicroservice(microservice));
-    Assert.assertEquals(null, oClient.getMicroservice("microserviceId"));
-    Assert.assertEquals(null, oClient.getMicroserviceInstance("consumerId", "providerId"));
-    Assert.assertEquals(false,
-        oClient.unregisterMicroserviceInstance("microserviceId", "microserviceInstanceId"));
-    Assert.assertEquals(null, oClient.heartbeat("microserviceId", "microserviceInstanceId"));
-    Assert.assertEquals(null,
-        oClient.findServiceInstance("selfMicroserviceId", "appId", "serviceName", "versionRule"));
-    Assert.assertEquals(null,
-        oClient.findServiceInstances("selfMicroserviceId", "appId", "serviceName", "versionRule", "0"));
+    Assert.assertNull(oClient.registerMicroservice(microservice));
+    Assert.assertNull(oClient.getMicroservice("microserviceId"));
+    Assert.assertNull(oClient.getMicroserviceInstance("consumerId", "providerId"));
+    Assert.assertFalse(oClient.unregisterMicroserviceInstance("microserviceId", "microserviceInstanceId"));
+    Assert.assertNull(oClient.heartbeat("microserviceId", "microserviceInstanceId"));
+    Assert.assertNull(oClient.findServiceInstance("selfMicroserviceId", "appId", "serviceName", "versionRule"));
+    Assert.assertNull(oClient.findServiceInstances("selfMicroserviceId", "appId", "serviceName", "versionRule", "0"));
 
     Assert.assertEquals("a", new ClientException("a").getMessage());
   }
@@ -324,14 +321,13 @@ public class TestServiceRegistryClientImpl {
       @Mock
       void httpDo(RequestContext requestContext, Handler<RestResponse> responseHandler) {
         Holder<GetServiceResponse> holder = Deencapsulation.getField(responseHandler, "arg$4");
-        GetServiceResponse serviceResp = Json
+        holder.value = Json
             .decodeValue(
                 "{\"service\":{\"serviceId\":\"serviceId\",\"framework\":null"
                     + ",\"registerBy\":null,\"environment\":null,\"appId\":\"appId\",\"serviceName\":null,"
                     + "\"alias\":null,\"version\":null,\"description\":null,\"level\":null,\"schemas\":[],"
                     + "\"paths\":[],\"status\":\"UP\",\"properties\":{},\"intance\":null}}",
                 GetServiceResponse.class);
-        holder.value = serviceResp;
         RequestParam requestParam = requestContext.getParams();
         Assert.assertEquals("global=true", requestParam.getQueryParams());
       }
@@ -351,11 +347,10 @@ public class TestServiceRegistryClientImpl {
       @Mock
       void httpDo(RequestContext requestContext, Handler<RestResponse> responseHandler) {
         Holder<GetSchemaResponse> holder = Deencapsulation.getField(responseHandler, "arg$4");
-        GetSchemaResponse schemasResp = Json
+        holder.value = Json
             .decodeValue(
                 "{ \"schema\": \"schema\", \"schemaId\":\"metricsEndpoint\",\"summary\":\"c1188d709631a9038874f9efc6eb894f\"}",
                 GetSchemaResponse.class);
-        holder.value = schemasResp;
         RequestParam requestParam = requestContext.getParams();
         Assert.assertEquals("global=true", requestParam.getQueryParams());
       }
@@ -545,4 +540,68 @@ public class TestServiceRegistryClientImpl {
       }
     }.run();
   }
+
+  @SuppressWarnings("deprecation")
+  @Test
+  public void undateMicroserviceInstanceStatus() {
+    HttpClientResponse httpClientResponse = new MockUp<HttpClientResponse>() {
+      @Mock
+      int statusCode() {
+        return 200;
+      }
+    }.getMockInstance();
+    new MockUp<RestUtils>() {
+      @Mock
+      void put(IpPort ipPort, String uri, RequestParam requestParam, Handler<RestResponse> responseHandler) {
+        Holder<HttpClientResponse> holder = Deencapsulation.getField(responseHandler, "arg$4");
+        holder.value = httpClientResponse;
+      }
+    };
+
+    boolean result = oClient.undateMicroserviceInstanceStatus("svcId", "instanceId", "UP");
+    Assert.assertTrue(result);
+  }
+
+  @SuppressWarnings("deprecation")
+  @Test
+  public void undateMicroserviceInstanceStatus_response_failure() {
+    HttpClientResponse httpClientResponse = new MockUp<HttpClientResponse>() {
+      @Mock
+      int statusCode() {
+        return 400;
+      }
+    }.getMockInstance();
+    new MockUp<RestUtils>() {
+      @Mock
+      void put(IpPort ipPort, String uri, RequestParam requestParam, Handler<RestResponse> responseHandler) {
+        Holder<HttpClientResponse> holder = Deencapsulation.getField(responseHandler, "arg$4");
+        holder.value = httpClientResponse;
+      }
+    };
+
+    boolean result = oClient.undateMicroserviceInstanceStatus("svcId", "instanceId", "UP");
+    Assert.assertFalse(result);
+  }
+
+  @SuppressWarnings("deprecation")
+  @Test
+  public void undateMicroserviceInstanceStatus_illegal_status() {
+    try {
+      oClient.undateMicroserviceInstanceStatus("svcId", "instanceId", null);
+      shouldThrowException();
+    } catch (NullPointerException e) {
+      Assert.assertEquals("Name is null", e.getMessage());
+    }
+    try {
+      oClient
+          .undateMicroserviceInstanceStatus("svcId", "instanceId", "IllegalStatus");
+      shouldThrowException();
+    } catch (IllegalArgumentException e) {
+      Assert.assertEquals("Invalid status: IllegalStatus", e.getMessage());
+    }
+  }
+
+  private void shouldThrowException() {
+    fail("an exception is expected");
+  }
 }


[servicecomb-java-chassis] 14/19: [SCB-1691] Each registry client use isolated IpPortManager

Posted by ya...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

yaohaishi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit 4abbc6def108d196679618491542da48318129ca
Author: yhs0092 <yh...@163.com>
AuthorDate: Sun Feb 16 16:05:09 2020 +0800

    [SCB-1691] Each registry client use isolated IpPortManager
---
 .../serviceregistry/client/IpPortManager.java      |  8 +--
 .../client/http/ServiceRegistryClientImpl.java     | 14 ++++-
 .../registry/AbstractServiceRegistry.java          |  9 +---
 .../registry/RemoteServiceRegistry.java            | 12 +----
 .../serviceregistry/client/TestIpPortManager.java  |  7 +--
 .../client/http/TestClientHttp.java                | 62 ++++++++++------------
 .../client/http/TestServiceRegistryClientImpl.java |  2 +-
 .../registry/TestRemoteServiceRegistry.java        |  8 ---
 8 files changed, 50 insertions(+), 72 deletions(-)

diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/IpPortManager.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/IpPortManager.java
index 18115c1..947a386 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/IpPortManager.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/IpPortManager.java
@@ -30,7 +30,9 @@ import org.apache.servicecomb.foundation.common.net.URIEndpointObject;
 import org.apache.servicecomb.serviceregistry.cache.CacheEndpoint;
 import org.apache.servicecomb.serviceregistry.cache.InstanceCache;
 import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager;
+import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManagerNew;
 import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
+import org.apache.servicecomb.serviceregistry.consumer.AppManager;
 import org.apache.servicecomb.serviceregistry.definition.DefinitionConst;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -40,7 +42,7 @@ public class IpPortManager {
 
   private ServiceRegistryConfig serviceRegistryConfig;
 
-  private InstanceCacheManager instanceCacheManager;
+  InstanceCacheManager instanceCacheManager;
 
   private String defaultTransport = "rest";
 
@@ -60,9 +62,9 @@ public class IpPortManager {
     return maxRetryTimes;
   }
 
-  public IpPortManager(ServiceRegistryConfig serviceRegistryConfig, InstanceCacheManager instanceCacheManager) {
+  public IpPortManager(ServiceRegistryConfig serviceRegistryConfig) {
     this.serviceRegistryConfig = serviceRegistryConfig;
-    this.instanceCacheManager = instanceCacheManager;
+    this.instanceCacheManager = new InstanceCacheManagerNew(new AppManager());
 
     defaultTransport = serviceRegistryConfig.getTransport();
     defaultIpPort = serviceRegistryConfig.getIpPort();
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java
index 5ab309d..1201907 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java
@@ -61,6 +61,8 @@ import org.apache.servicecomb.serviceregistry.client.ClientException;
 import org.apache.servicecomb.serviceregistry.client.IpPortManager;
 import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient;
 import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
+import org.apache.servicecomb.serviceregistry.task.HeartbeatResult;
+import org.apache.servicecomb.serviceregistry.task.MicroserviceInstanceHeartbeatTask;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -68,6 +70,7 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
+import com.google.common.eventbus.Subscribe;
 
 import io.netty.handler.codec.http.HttpStatusClass;
 import io.vertx.core.Handler;
@@ -93,8 +96,8 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
 
   private WebsocketClientUtil websocketClientUtil;
 
-  public ServiceRegistryClientImpl(IpPortManager ipPortManager, ServiceRegistryConfig serviceRegistryConfig) {
-    this.ipPortManager = ipPortManager;
+  public ServiceRegistryClientImpl(ServiceRegistryConfig serviceRegistryConfig) {
+    this.ipPortManager = new IpPortManager(serviceRegistryConfig);
     this.restClientUtil = new RestClientUtil(serviceRegistryConfig);
     this.websocketClientUtil = new WebsocketClientUtil(serviceRegistryConfig);
   }
@@ -943,4 +946,11 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
     }
     return false;
   }
+
+  @Subscribe
+  public void onMicroserviceHeartbeatTask(MicroserviceInstanceHeartbeatTask event) {
+    if (HeartbeatResult.SUCCESS.equals(event.getHeartbeatResult())) {
+      ipPortManager.initAutoDiscovery();
+    }
+  }
 }
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java
index 214968a..a8c4bc3 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java
@@ -39,7 +39,6 @@ import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceFactory;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
 import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent;
-import org.apache.servicecomb.serviceregistry.client.IpPortManager;
 import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient;
 import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances;
 import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
@@ -77,8 +76,6 @@ public abstract class AbstractServiceRegistry implements ServiceRegistry {
 
   protected Microservice microservice;
 
-  protected IpPortManager ipPortManager;
-
   protected ServiceRegistryClient srClient;
 
   protected ServiceRegistryConfig serviceRegistryConfig;
@@ -102,9 +99,9 @@ public abstract class AbstractServiceRegistry implements ServiceRegistry {
 
   @Override
   public void init() {
-    ipPortManager = new IpPortManager(serviceRegistryConfig, RegistryUtils.getInstanceCacheManager());
     if (srClient == null) {
       srClient = createServiceRegistryClient();
+      eventBus.register(srClient);
     }
 
     createServiceCenterTask();
@@ -144,10 +141,6 @@ public abstract class AbstractServiceRegistry implements ServiceRegistry {
     this.srClient = serviceRegistryClient;
   }
 
-  public IpPortManager getIpPortManager() {
-    return ipPortManager;
-  }
-
   @Override
   public String getAppId() {
     return microservice.getAppId();
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java
index 2002177..a53e4ac 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java
@@ -27,13 +27,10 @@ import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient;
 import org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl;
 import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
 import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition;
-import org.apache.servicecomb.serviceregistry.task.HeartbeatResult;
-import org.apache.servicecomb.serviceregistry.task.MicroserviceInstanceHeartbeatTask;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.eventbus.EventBus;
-import com.google.common.eventbus.Subscribe;
 
 public class RemoteServiceRegistry extends AbstractServiceRegistry {
   private static final Logger LOGGER = LoggerFactory.getLogger(RemoteServiceRegistry.class);
@@ -71,7 +68,7 @@ public class RemoteServiceRegistry extends AbstractServiceRegistry {
 
   @Override
   protected ServiceRegistryClient createServiceRegistryClient() {
-    return new ServiceRegistryClientImpl(ipPortManager, serviceRegistryConfig);
+    return new ServiceRegistryClientImpl(serviceRegistryConfig);
   }
 
   @Override
@@ -96,13 +93,6 @@ public class RemoteServiceRegistry extends AbstractServiceRegistry {
     }
   }
 
-  @Subscribe
-  public void onMicroserviceHeartbeatTask(MicroserviceInstanceHeartbeatTask event) {
-    if (HeartbeatResult.SUCCESS.equals(event.getHeartbeatResult())) {
-      ipPortManager.initAutoDiscovery();
-    }
-  }
-
   public ScheduledThreadPoolExecutor getTaskPool() {
     return this.taskPool;
   }
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/TestIpPortManager.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/TestIpPortManager.java
index f3a747b..595673e 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/TestIpPortManager.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/TestIpPortManager.java
@@ -48,16 +48,12 @@ public class TestIpPortManager {
 
   AbstractServiceRegistry serviceRegistry;
 
-  IpPortManager manager;
-
   @Before
   public void setup() {
     ConfigUtil.createLocalConfig();
     serviceRegistry = (AbstractServiceRegistry) ServiceRegistryFactory.createLocal();
     serviceRegistry.setServiceRegistryClient(srClient);
     serviceRegistry.init();
-
-    manager = serviceRegistry.getIpPortManager();
   }
 
   @Test
@@ -79,7 +75,8 @@ public class TestIpPortManager {
       }
     };
 
-    IpPortManager manager = new IpPortManager(config, cacheManager);
+    IpPortManager manager = new IpPortManager(config);
+    manager.instanceCacheManager = cacheManager;
     IpPort address1 = manager.getAvailableAddress();
 
     if (address1.getPort() == 9980) {
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestClientHttp.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestClientHttp.java
index 48ab807..bea5c61 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestClientHttp.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestClientHttp.java
@@ -24,7 +24,6 @@ import org.apache.servicecomb.foundation.vertx.AsyncResultCallback;
 import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceFactory;
-import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager;
 import org.apache.servicecomb.serviceregistry.client.Endpoints;
 import org.apache.servicecomb.serviceregistry.client.IpPortManager;
 import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
@@ -90,36 +89,31 @@ public class TestClientHttp {
     MicroserviceFactory microserviceFactory = new MicroserviceFactory();
     Microservice microservice = microserviceFactory.create("app", "ms");
 
-    ServiceRegistryClientImpl oClient = new ServiceRegistryClientImpl(manager, ServiceRegistryConfig.INSTANCE);
+    ServiceRegistryClientImpl oClient = new ServiceRegistryClientImpl(ServiceRegistryConfig.INSTANCE);
     oClient.init();
     oClient.registerMicroservice(microservice);
     oClient.registerMicroserviceInstance(microservice.getInstance());
-    Assert.assertEquals(null, oClient.getMicroservice(microservice.getServiceId()));
-    Assert.assertEquals(null, oClient.getMicroserviceInstance("testConsumerID", "testproviderID"));
-    Assert.assertEquals(null,
-        oClient.findServiceInstance(microservice.getServiceId(),
-            microservice.getAppId(),
-            microservice.getServiceName(),
-            microservice.getVersion()));
-    Assert.assertEquals(null,
-        oClient.findServiceInstances(microservice.getServiceId(),
-            microservice.getAppId(),
-            microservice.getServiceName(),
-            microservice.getVersion(),
-            "0"));
-    Assert.assertEquals(null,
-        oClient.getMicroserviceId(microservice.getAppId(),
-            microservice.getServiceName(),
-            microservice.getVersion(),
-            microservice.getEnvironment()));
-    Assert.assertEquals(null,
-        oClient.heartbeat(microservice.getServiceId(),
-            microservice.getInstance().getInstanceId()));
+    Assert.assertNull(oClient.getMicroservice(microservice.getServiceId()));
+    Assert.assertNull(oClient.getMicroserviceInstance("testConsumerID", "testproviderID"));
+    Assert.assertNull(oClient.findServiceInstance(microservice.getServiceId(),
+        microservice.getAppId(),
+        microservice.getServiceName(),
+        microservice.getVersion()));
+    Assert.assertNull(oClient.findServiceInstances(microservice.getServiceId(),
+        microservice.getAppId(),
+        microservice.getServiceName(),
+        microservice.getVersion(),
+        "0"));
+    Assert.assertNull(oClient.getMicroserviceId(microservice.getAppId(),
+        microservice.getServiceName(),
+        microservice.getVersion(),
+        microservice.getEnvironment()));
+    Assert.assertNull(oClient.heartbeat(microservice.getServiceId(),
+        microservice.getInstance().getInstanceId()));
     oClient.watch("",
         Mockito.mock(AsyncResultCallback.class));
-    Assert.assertEquals(false,
-        oClient.unregisterMicroserviceInstance(microservice.getServiceId(),
-            microservice.getInstance().getInstanceId()));
+    Assert.assertFalse(oClient.unregisterMicroserviceInstance(microservice.getServiceId(),
+        microservice.getInstance().getInstanceId()));
   }
 
   @Test
@@ -133,12 +127,12 @@ public class TestClientHttp {
     Assert.assertEquals("//test", oContext.getUri());
     Assert.assertEquals(io.vertx.core.http.HttpMethod.POST, oContext.getMethod());
     Assert.assertEquals(8080, oContext.getIpPort().getPort());
-    Assert.assertEquals(null, oContext.getParams());
+    Assert.assertNull(oContext.getParams());
 
     RestResponse oResponse = new RestResponse(null, null);
     oResponse.setRequestContext(oContext);
     Assert.assertEquals(oContext, oResponse.getRequestContext());
-    Assert.assertEquals(null, oResponse.getResponse());
+    Assert.assertNull(oResponse.getResponse());
   }
 
   @Test
@@ -150,24 +144,24 @@ public class TestClientHttp {
     oParam.addHeader("testKey", "testValue");
     oParam.addQueryParam("testParam", "ValueParam");
     oParam.addQueryParam("testParam1", "ValueParam");
-    Assert.assertEquals(null, oParam.getCookies());
-    Assert.assertEquals(null, oParam.getBody());
+    Assert.assertNull(oParam.getCookies());
+    Assert.assertNull(oParam.getBody());
     Assert.assertNotEquals(null, oParam.getHeaders());
     Assert.assertNotEquals(null, oParam.getQueryParams());
     oParam.setQueryParams(null);
     Assert.assertEquals("", oParam.getQueryParams());
     oParam.setFormFields(null);
-    Assert.assertEquals(null, oParam.getFormFields());
+    Assert.assertNull(oParam.getFormFields());
     Endpoints oEndpoints = new Endpoints();
     oEndpoints.setInstances(null);
     oEndpoints.setVersion("1.0");
-    Assert.assertEquals(null, oEndpoints.getInstances());
+    Assert.assertNull(oEndpoints.getInstances());
     Assert.assertEquals("1.0", oEndpoints.getVersion());
   }
 
   @Test
-  public void testIpPortManager(@Mocked InstanceCacheManager instanceCacheManager) throws Exception {
-    IpPortManager oManager = new IpPortManager(ServiceRegistryConfig.INSTANCE, instanceCacheManager);
+  public void testIpPortManager() {
+    IpPortManager oManager = new IpPortManager(ServiceRegistryConfig.INSTANCE);
     IpPort oIPPort = oManager.getNextAvailableAddress(new IpPort("", 33));
     Assert.assertEquals(oIPPort.getHostOrIp(), oManager.getAvailableAddress().getHostOrIp());
   }
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java
index 6e260d9..a63b7bc 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java
@@ -78,7 +78,7 @@ public class TestServiceRegistryClientImpl {
 
   @Before
   public void setUp() throws Exception {
-    oClient = new ServiceRegistryClientImpl(ipPortManager, ServiceRegistryConfig.buildFromConfiguration());
+    oClient = new ServiceRegistryClientImpl(ServiceRegistryConfig.buildFromConfiguration());
 
     new MockUp<RegistryUtils>() {
       @Mock
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestRemoteServiceRegistry.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestRemoteServiceRegistry.java
index c035aae..b562c29 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestRemoteServiceRegistry.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestRemoteServiceRegistry.java
@@ -78,18 +78,10 @@ public class TestRemoteServiceRegistry {
       {
         definition.getConfiguration();
         result = ConfigUtil.createLocalConfig();
-        config.getIpPort();
-        result = ipPortList;
-        config.getTransport();
-        result = "rest";
-        config.isRegistryAutoDiscovery();
-        result = true;
         config.getHeartbeatInterval();
         result = 30;
         config.getInstancePullInterval();
         result = 30;
-        config.isWatch();
-        result = false;
         config.getRegistryName();
         result = "TestRegistry";
         SPIServiceUtils.getOrLoadSortedService(ServiceRegistryTaskInitializer.class);


[servicecomb-java-chassis] 12/19: [SCB-1691] Each ServiceRegistry uses an isolated EventBus

Posted by ya...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

yaohaishi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit c79d5e122b2d526fe4227ecbfb5061f5d174859e
Author: yhs0092 <yh...@163.com>
AuthorDate: Tue Feb 11 21:16:33 2020 +0800

    [SCB-1691] Each ServiceRegistry uses an isolated EventBus
---
 .../servicecomb/serviceregistry/RegistryUtils.java | 38 +++++++++++++++++++---
 .../registry/ServiceRegistryFactory.java           |  8 +++++
 2 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
index 49f28e2..3f99eae 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
@@ -25,6 +25,7 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.regex.Matcher;
@@ -52,10 +53,13 @@ import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache;
 import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache.MicroserviceCacheStatus;
 import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCacheKey;
 import org.apache.servicecomb.serviceregistry.swagger.SwaggerLoader;
+import org.apache.servicecomb.serviceregistry.task.MicroserviceInstanceRegisterTask;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.util.StringUtils;
 
 import com.google.common.base.Charsets;
+import com.google.common.eventbus.Subscribe;
 import com.google.common.hash.Hashing;
 import com.netflix.config.DynamicPropertyFactory;
 
@@ -115,14 +119,13 @@ public final class RegistryUtils {
 
   private static void initializeServiceRegistries(MicroserviceDefinition microserviceDefinition) {
     serviceRegistry =
-        ServiceRegistryFactory
-            .create(EventManager.eventBus, ServiceRegistryConfig.INSTANCE, microserviceDefinition);
+        ServiceRegistryFactory.create(ServiceRegistryConfig.INSTANCE, microserviceDefinition);
     EXTRA_SERVICE_REGISTRY_CONFIGS.forEach((k, v) -> {
-      ServiceRegistry serviceRegistry = ServiceRegistryFactory
-          .create(EventManager.getEventBus(), v, microserviceDefinition);
+      ServiceRegistry serviceRegistry = ServiceRegistryFactory.create(v, microserviceDefinition);
       addExtraServiceRegistry(serviceRegistry);
     });
     executeOnEachServiceRegistry(ServiceRegistry::init);
+    executeOnEachServiceRegistry(AfterServiceInstanceRegistryHandler::new);
   }
 
   public static void run() {
@@ -411,4 +414,31 @@ public final class RegistryUtils {
           "Illegal registry name, the format should be " + ServiceRegistry.REGISTRY_NAME_FORMAT);
     }
   }
+
+  public static class AfterServiceInstanceRegistryHandler {
+    private static AtomicInteger instanceRegisterCounter = new AtomicInteger(EXTRA_SERVICE_REGISTRIES.size() + 1);
+
+    private ServiceRegistry serviceRegistry;
+
+    AfterServiceInstanceRegistryHandler(ServiceRegistry serviceRegistry) {
+      this.serviceRegistry = serviceRegistry;
+      serviceRegistry.getEventBus().register(this);
+    }
+
+    @Subscribe
+    public void afterRegistryInstance(MicroserviceInstanceRegisterTask microserviceInstanceRegisterTask) {
+      LOGGER.info("receive MicroserviceInstanceRegisterTask event of [{}]", serviceRegistry.getName());
+      if (StringUtils.isEmpty(serviceRegistry.getMicroserviceInstance().getInstanceId())) {
+        return;
+      }
+
+      LOGGER.info("ServiceRegistry[{}] has completed instance registry", serviceRegistry.getName());
+      EventManager.unregister(this);
+
+      if (instanceRegisterCounter.decrementAndGet() > 0) {
+        return;
+      }
+      EventManager.getEventBus().post(microserviceInstanceRegisterTask);
+    }
+  }
 }
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryFactory.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryFactory.java
index 0dab855..a672bbf 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryFactory.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryFactory.java
@@ -52,8 +52,16 @@ public final class ServiceRegistryFactory {
     return new LocalServiceRegistry(eventBus, serviceRegistryConfig, microserviceDefinition).localFile(localFile);
   }
 
+  public static ServiceRegistry create(ServiceRegistryConfig serviceRegistryConfig,
+      MicroserviceDefinition microserviceDefinition) {
+    return create(null, serviceRegistryConfig, microserviceDefinition);
+  }
+
   public static ServiceRegistry create(EventBus eventBus, ServiceRegistryConfig serviceRegistryConfig,
       MicroserviceDefinition microserviceDefinition) {
+    if (null == eventBus) {
+      eventBus = new SimpleEventBus();
+    }
     String localModeFile = System.getProperty(LocalServiceRegistryClientImpl.LOCAL_REGISTRY_FILE_KEY);
     if (!StringUtils.isEmpty(localModeFile)) {
       LOGGER.info(


[servicecomb-java-chassis] 08/19: [SCB-1691] replace RestUtils and WebsocketUtils in ServiceRegistryClientImpl

Posted by ya...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

yaohaishi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit 1a920ebf93cfb2dd8e5a0360693fcb12231def0b
Author: yhs0092 <yh...@163.com>
AuthorDate: Wed Jan 15 14:57:54 2020 +0800

    [SCB-1691] replace RestUtils and WebsocketUtils in ServiceRegistryClientImpl
---
 .../client/http/ServiceRegistryClientImpl.java     | 50 +++++++++++---------
 .../registry/RemoteServiceRegistry.java            |  2 +-
 .../serviceregistry/client/http/RestUtilsTest.java |  1 +
 .../client/http/TestClientHttp.java                | 18 ++++++--
 .../client/http/TestServiceRegistryClientImpl.java | 53 +++++++++-------------
 5 files changed, 65 insertions(+), 59 deletions(-)

diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java
index ed2e369..5ab309d 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java
@@ -89,8 +89,14 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
   // extract this, ServiceRegistryClient is better to be no status.
   private Map<String, Boolean> watchServices = new ConcurrentHashMap<>();
 
-  public ServiceRegistryClientImpl(IpPortManager ipPortManager) {
+  private RestClientUtil restClientUtil;
+
+  private WebsocketClientUtil websocketClientUtil;
+
+  public ServiceRegistryClientImpl(IpPortManager ipPortManager, ServiceRegistryConfig serviceRegistryConfig) {
     this.ipPortManager = ipPortManager;
+    this.restClientUtil = new RestClientUtil(serviceRegistryConfig);
+    this.websocketClientUtil = new WebsocketClientUtil(serviceRegistryConfig);
   }
 
   private LoadingCache<String, Map<String, String>> schemaCache = CacheBuilder.newBuilder()
@@ -113,7 +119,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
     LOGGER.warn("invoke service [{}] failed, retry.", requestContext.getUri());
     requestContext.setIpPort(ipPortManager.getNextAvailableAddress(requestContext.getIpPort()));
     requestContext.incrementRetryTimes();
-    RestUtils.httpDo(requestContext, responseHandler);
+    restClientUtil.httpDo(requestContext, responseHandler);
   }
 
   @VisibleForTesting
@@ -197,7 +203,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
   }
 
   // temporary copy from syncHandler
-  // we will use swagger invocation to replace RestUtils later.
+  // we will use swagger invocation to replace restClientUtil later.
   private Handler<RestResponse> syncHandlerEx(CountDownLatch countDownLatch, Holder<ResponseWrapper> holder) {
     return restResponse -> {
       RequestContext requestContext = restResponse.getRequestContext();
@@ -284,7 +290,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
     IpPort ipPort = ipPortManager.getAvailableAddress();
 
     CountDownLatch countDownLatch = new CountDownLatch(1);
-    RestUtils.get(ipPort,
+    restClientUtil.get(ipPort,
         Const.REGISTRY_API.MICROSERVICE_OPERATION_ALL,
         new RequestParam(),
         syncHandler(countDownLatch, GetAllServicesResponse.class, holder));
@@ -305,7 +311,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
     IpPort ipPort = ipPortManager.getAvailableAddress();
 
     CountDownLatch countDownLatch = new CountDownLatch(1);
-    RestUtils.get(ipPort,
+    restClientUtil.get(ipPort,
         Const.REGISTRY_API.MICROSERVICE_EXISTENCE,
         new RequestParam().addQueryParam("type", "microservice")
             .addQueryParam("appId", appId)
@@ -334,7 +340,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
     IpPort ipPort = ipPortManager.getAvailableAddress();
 
     CountDownLatch countDownLatch = new CountDownLatch(1);
-    RestUtils.get(ipPort,
+    restClientUtil.get(ipPort,
         Const.REGISTRY_API.MICROSERVICE_EXISTENCE,
         new RequestParam().addQueryParam("type", "schema")
             .addQueryParam("serviceId", microserviceId)
@@ -363,7 +369,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
       byte[] body = JsonUtils.writeValueAsBytes(request);
 
       CountDownLatch countDownLatch = new CountDownLatch(1);
-      RestUtils.put(ipPort,
+      restClientUtil.put(ipPort,
           String.format(Const.REGISTRY_API.MICROSERVICE_SCHEMA, microserviceId, schemaId),
           new RequestParam().setBody(body),
           syncHandlerEx(countDownLatch, holder));
@@ -421,7 +427,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
     if (global) {
       param.addQueryParam("global", "true");
     }
-    RestUtils.get(ipPort,
+    restClientUtil.get(ipPort,
         String.format(Const.REGISTRY_API.MICROSERVICE_SCHEMA, microserviceId, schemaId),
         param,
         syncHandler(countDownLatch, GetSchemaResponse.class, holder));
@@ -464,7 +470,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
       requestParam.addQueryParam("global", "true");
     }
 
-    RestUtils.get(ipPort,
+    restClientUtil.get(ipPort,
         String.format(url, microserviceId),
         requestParam,
         syncHandler(countDownLatch, GetSchemasResponse.class, holder));
@@ -500,7 +506,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
       }
 
       CountDownLatch countDownLatch = new CountDownLatch(1);
-      RestUtils.post(ipPort,
+      restClientUtil.post(ipPort,
           Const.REGISTRY_API.MICROSERVICE_OPERATION_ALL,
           new RequestParam().setBody(body),
           syncHandler(countDownLatch, CreateServiceResponse.class, holder));
@@ -532,7 +538,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
     if (global) {
       param.addQueryParam("global", "true");
     }
-    RestUtils.get(ipPort,
+    restClientUtil.get(ipPort,
         String.format(Const.REGISTRY_API.MICROSERVICE_OPERATION_ONE, microserviceId),
         param,
         syncHandler(countDownLatch, GetServiceResponse.class, holder));
@@ -567,7 +573,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
       }
 
       CountDownLatch countDownLatch = new CountDownLatch(1);
-      RestUtils.post(ipPort,
+      restClientUtil.post(ipPort,
           String.format(Const.REGISTRY_API.MICROSERVICE_INSTANCE_OPERATION_ALL, instance.getServiceId()),
           new RequestParam().setBody(body),
           syncHandler(countDownLatch, RegisterInstanceResponse.class, holder));
@@ -587,7 +593,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
     IpPort ipPort = ipPortManager.getAvailableAddress();
 
     CountDownLatch countDownLatch = new CountDownLatch(1);
-    RestUtils.get(ipPort,
+    restClientUtil.get(ipPort,
         String.format(Const.REGISTRY_API.MICROSERVICE_INSTANCE_OPERATION_ALL, providerId),
         new RequestParam().addHeader("X-ConsumerId", consumerId),
         syncHandler(countDownLatch, GetInstancesResponse.class, holder));
@@ -608,7 +614,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
     IpPort ipPort = ipPortManager.getAvailableAddress();
 
     CountDownLatch countDownLatch = new CountDownLatch(1);
-    RestUtils.delete(ipPort,
+    restClientUtil.delete(ipPort,
         String.format(Const.REGISTRY_API.MICROSERVICE_INSTANCE_OPERATION_ONE, microserviceId, microserviceInstanceId),
         new RequestParam(),
         syncHandler(countDownLatch, HttpClientResponse.class, holder));
@@ -635,7 +641,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
     IpPort ipPort = ipPortManager.getAvailableAddress();
 
     CountDownLatch countDownLatch = new CountDownLatch(1);
-    RestUtils.put(ipPort,
+    restClientUtil.put(ipPort,
         String.format(Const.REGISTRY_API.MICROSERVICE_HEARTBEAT, microserviceId, microserviceInstanceId),
         new RequestParam().setTimeout(ServiceRegistryConfig.INSTANCE.getHeartBeatRequestTimeout()),
         syncHandler(countDownLatch, HttpClientResponse.class, holder));
@@ -679,7 +685,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
           String url = String.format(Const.REGISTRY_API.MICROSERVICE_WATCH, selfMicroserviceId);
 
           IpPort ipPort = ipPortManager.getAvailableAddress();
-          WebsocketUtils.open(ipPort, url, o -> {
+          websocketClientUtil.open(ipPort, url, o -> {
             onOpen.success(o);
             LOGGER.info(
                 "watching microservice {} successfully, "
@@ -753,7 +759,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
       requestParam.addQueryParam("rev", revision);
     }
 
-    RestUtils.get(ipPort,
+    restClientUtil.get(ipPort,
         Const.REGISTRY_API.MICROSERVICE_INSTANCES,
         requestParam,
         syncHandlerForInstances(countDownLatch, microserviceInstances));
@@ -805,7 +811,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
       }
 
       CountDownLatch countDownLatch = new CountDownLatch(1);
-      RestUtils.put(ipPort,
+      restClientUtil.put(ipPort,
           String.format(Const.REGISTRY_API.MICROSERVICE_PROPERTIES, microserviceId),
           new RequestParam().setBody(body),
           syncHandler(countDownLatch, HttpClientResponse.class, holder));
@@ -842,7 +848,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
       }
 
       CountDownLatch countDownLatch = new CountDownLatch(1);
-      RestUtils.put(ipPort,
+      restClientUtil.put(ipPort,
           String.format(Const.REGISTRY_API.MICROSERVICE_INSTANCE_PROPERTIES, microserviceId, microserviceInstanceId),
           new RequestParam().setBody(body),
           syncHandler(countDownLatch, HttpClientResponse.class, holder));
@@ -869,7 +875,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
       Holder<MicroserviceInstanceResponse> holder = new Holder<>();
       IpPort ipPort = ipPortManager.getAvailableAddress();
       CountDownLatch countDownLatch = new CountDownLatch(1);
-      RestUtils.get(ipPort,
+      restClientUtil.get(ipPort,
           String.format(Const.REGISTRY_API.MICROSERVICE_INSTANCE_OPERATION_ONE, serviceId, instanceId),
           new RequestParam().addHeader("X-ConsumerId", serviceId).addQueryParam("global", "true"),
           syncHandler(countDownLatch, MicroserviceInstanceResponse.class, holder));
@@ -890,7 +896,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
     IpPort ipPort = ipPortManager.getAvailableAddress();
 
     CountDownLatch countDownLatch = new CountDownLatch(1);
-    RestUtils.get(ipPort,
+    restClientUtil.get(ipPort,
         Const.REGISTRY_API.SERVICECENTER_VERSION,
         new RequestParam(),
         syncHandler(countDownLatch, ServiceCenterInfo.class, holder));
@@ -920,7 +926,7 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
       Map<String, String[]> queryParams = new HashMap<>();
       queryParams.put("value", new String[] {status.toString()});
       CountDownLatch countDownLatch = new CountDownLatch(1);
-      RestUtils.put(ipPort, url, new RequestParam().setQueryParams(queryParams),
+      restClientUtil.put(ipPort, url, new RequestParam().setQueryParams(queryParams),
           syncHandler(countDownLatch, HttpClientResponse.class, holder));
       countDownLatch.await();
       if (holder.value != null) {
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java
index dfeee99..b6af226 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java
@@ -72,7 +72,7 @@ public class RemoteServiceRegistry extends AbstractServiceRegistry {
 
   @Override
   protected ServiceRegistryClient createServiceRegistryClient() {
-    return new ServiceRegistryClientImpl(ipPortManager);
+    return new ServiceRegistryClientImpl(ipPortManager, serviceRegistryConfig);
   }
 
   @Override
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/RestUtilsTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/RestUtilsTest.java
index ad72502..336a805 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/RestUtilsTest.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/RestUtilsTest.java
@@ -28,6 +28,7 @@ import org.junit.Test;
 import io.vertx.core.MultiMap;
 import io.vertx.core.http.HttpMethod;
 
+@SuppressWarnings("deprecation")
 public class RestUtilsTest {
   @Test
   public void defaultHeadersContainServiceRegistryAndAuthentication() throws Exception {
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestClientHttp.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestClientHttp.java
index b58088d..48ab807 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestClientHttp.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestClientHttp.java
@@ -63,24 +63,34 @@ public class TestClientHttp {
       public void await() throws InterruptedException {
       }
     };
-    new MockUp<RestUtils>() {
+    new MockUp<RestClientUtil>() {
       @Mock
       void httpDo(RequestContext requestContext, Handler<RestResponse> responseHandler) {
       }
     };
-
-    new MockUp<WebsocketUtils>() {
+    new MockUp<WebsocketClientUtil>() {
       @Mock
       void open(IpPort ipPort, String url, Handler<Void> onOpen, Handler<Void> onClose,
           Handler<Buffer> onMessage, Handler<Throwable> onException,
           Handler<Throwable> onConnectFailed) {
       }
     };
+    // mock up this two client pool, since this UT case doesn't require the client pool actually boot up.
+    new MockUp<HttpClientPool>() {
+      @Mock
+      void create() {
+      }
+    };
+    new MockUp<WebsocketClientPool>() {
+      @Mock
+      void create() {
+      }
+    };
 
     MicroserviceFactory microserviceFactory = new MicroserviceFactory();
     Microservice microservice = microserviceFactory.create("app", "ms");
 
-    ServiceRegistryClientImpl oClient = new ServiceRegistryClientImpl(manager);
+    ServiceRegistryClientImpl oClient = new ServiceRegistryClientImpl(manager, ServiceRegistryConfig.INSTANCE);
     oClient.init();
     oClient.registerMicroservice(microservice);
     oClient.registerMicroserviceInstance(microservice.getInstance());
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java
index 3a7662b..6e260d9 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java
@@ -45,6 +45,7 @@ import org.apache.servicecomb.serviceregistry.api.response.GetServiceResponse;
 import org.apache.servicecomb.serviceregistry.client.ClientException;
 import org.apache.servicecomb.serviceregistry.client.IpPortManager;
 import org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl.ResponseWrapper;
+import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
 import org.apache.servicecomb.serviceregistry.definition.DefinitionConst;
 import org.junit.After;
 import org.junit.Assert;
@@ -60,7 +61,6 @@ import io.vertx.core.Handler;
 import io.vertx.core.buffer.Buffer;
 import io.vertx.core.http.HttpClientOptions;
 import io.vertx.core.http.HttpClientResponse;
-import io.vertx.core.http.HttpMethod;
 import io.vertx.core.json.Json;
 import mockit.Deencapsulation;
 import mockit.Expectations;
@@ -78,13 +78,7 @@ public class TestServiceRegistryClientImpl {
 
   @Before
   public void setUp() throws Exception {
-    oClient = new ServiceRegistryClientImpl(ipPortManager);
-
-    new MockUp<RestUtils>() {
-      @Mock
-      void httpDo(RequestContext requestContext, Handler<RestResponse> responseHandler) {
-      }
-    };
+    oClient = new ServiceRegistryClientImpl(ipPortManager, ServiceRegistryConfig.buildFromConfiguration());
 
     new MockUp<RegistryUtils>() {
       @Mock
@@ -216,7 +210,7 @@ public class TestServiceRegistryClientImpl {
         };
       }
     };
-    new MockUp<RestUtils>() {
+    new MockUp<RestClientUtil>() {
       @Mock
       void httpDo(RequestContext requestContext, Handler<RestResponse> responseHandler) {
         responseHandler.handle(null);
@@ -248,7 +242,7 @@ public class TestServiceRegistryClientImpl {
         };
       }
     };
-    new MockUp<RestUtils>() {
+    new MockUp<RestClientUtil>() {
       @Mock
       void httpDo(RequestContext requestContext, Handler<RestResponse> responseHandler) {
         responseHandler.handle(null);
@@ -304,7 +298,7 @@ public class TestServiceRegistryClientImpl {
     String microserviceId = "msId";
     String schemaId = "schemaId";
 
-    new MockUp<RestUtils>() {
+    new MockUp<RestClientUtil>() {
       @Mock
       void httpDo(RequestContext requestContext, Handler<RestResponse> responseHandler) {
         Holder<GetExistenceResponse> holder = Deencapsulation.getField(responseHandler, "arg$4");
@@ -317,7 +311,7 @@ public class TestServiceRegistryClientImpl {
   @Test
   public void getAggregatedMicroservice() {
     String microserviceId = "msId";
-    new MockUp<RestUtils>() {
+    new MockUp<RestClientUtil>() {
       @Mock
       void httpDo(RequestContext requestContext, Handler<RestResponse> responseHandler) {
         Holder<GetServiceResponse> holder = Deencapsulation.getField(responseHandler, "arg$4");
@@ -342,7 +336,7 @@ public class TestServiceRegistryClientImpl {
     String microserviceId = "msId";
     String schemaId = "schemaId";
 
-    new MockUp<RestUtils>() {
+    new MockUp<RestClientUtil>() {
 
       @Mock
       void httpDo(RequestContext requestContext, Handler<RestResponse> responseHandler) {
@@ -376,7 +370,7 @@ public class TestServiceRegistryClientImpl {
   public void getSchemas() {
     String microserviceId = "msId";
 
-    new MockUp<RestUtils>() {
+    new MockUp<RestClientUtil>() {
       @Mock
       void httpDo(RequestContext requestContext, Handler<RestResponse> responseHandler) {
         Holder<GetSchemasResponse> holder = Deencapsulation.getField(responseHandler, "arg$4");
@@ -399,7 +393,7 @@ public class TestServiceRegistryClientImpl {
   public void getSchemasForNew() {
     String microserviceId = "msId";
 
-    new MockUp<RestUtils>() {
+    new MockUp<RestClientUtil>() {
       @Mock
       void httpDo(RequestContext requestContext, Handler<RestResponse> responseHandler) {
         Holder<GetSchemasResponse> holder = Deencapsulation.getField(responseHandler, "arg$4");
@@ -422,7 +416,7 @@ public class TestServiceRegistryClientImpl {
   public void getSchemasFailed() {
     String microserviceId = "msId";
 
-    new MockUp<RestUtils>() {
+    new MockUp<RestClientUtil>() {
       @Mock
       void httpDo(RequestContext requestContext, Handler<RestResponse> responseHandler) {
         Holder<GetSchemasResponse> holder = Deencapsulation.getField(responseHandler, "arg$4");
@@ -437,7 +431,7 @@ public class TestServiceRegistryClientImpl {
 
   @Test
   public void testFindServiceInstance() {
-    new MockUp<RestUtils>() {
+    new MockUp<RestClientUtil>() {
       @Mock
       void get(IpPort ipPort, String uri, RequestParam requestParam,
           Handler<RestResponse> responseHandler) {
@@ -449,7 +443,7 @@ public class TestServiceRegistryClientImpl {
 
   @Test
   public void findServiceInstance_consumerId_null() {
-    new MockUp<RestUtils>() {
+    new MockUp<RestClientUtil>() {
       @Mock
       void get(IpPort ipPort, String uri, RequestParam requestParam,
           Handler<RestResponse> responseHandler) {
@@ -461,7 +455,7 @@ public class TestServiceRegistryClientImpl {
   }
 
   @Test
-  public void findServiceInstances_microserviceNotExist(@Mocked RequestContext requestContext) {
+  public void findServiceInstances_microserviceNotExist() {
     HttpClientResponse response = new MockUp<HttpClientResponse>() {
       @Mock
       int statusCode() {
@@ -475,18 +469,13 @@ public class TestServiceRegistryClientImpl {
         return null;
       }
     }.getMockInstance();
-    RestResponse restResponse = new RestResponse(requestContext, response);
-    new MockUp<RestUtils>() {
-      @Mock
-      void get(IpPort ipPort, String uri, RequestParam requestParam,
-          Handler<RestResponse> responseHandler) {
-        Assert.assertEquals("appId=appId&global=true&serviceName=serviceName&version=0.0.0.0%2B",
-            requestParam.getQueryParams());
-        httpDo(RestUtils.createRequestContext(HttpMethod.GET, ipPort, uri, requestParam), responseHandler);
-      }
-
+    RestResponse restResponse = new RestResponse(null, response);
+    new MockUp<RestClientUtil>() {
       @Mock
       void httpDo(RequestContext requestContext, Handler<RestResponse> responseHandler) {
+        Assert.assertEquals("appId=appId&global=true&serviceName=serviceName&version=0.0.0.0%2B",
+            requestContext.getParams().getQueryParams());
+        restResponse.setRequestContext(requestContext);
         responseHandler.handle(restResponse);
       }
     };
@@ -506,7 +495,7 @@ public class TestServiceRegistryClientImpl {
     serviceCenterInfo.setApiVersion("x.x.x");
     serviceCenterInfo.setConfig(new ServiceCenterConfig());
 
-    new MockUp<RestUtils>() {
+    new MockUp<RestClientUtil>() {
       @Mock
       void httpDo(RequestContext requestContext, Handler<RestResponse> responseHandler) {
         Holder<ServiceCenterInfo> holder = Deencapsulation.getField(responseHandler, "arg$4");
@@ -550,7 +539,7 @@ public class TestServiceRegistryClientImpl {
         return 200;
       }
     }.getMockInstance();
-    new MockUp<RestUtils>() {
+    new MockUp<RestClientUtil>() {
       @Mock
       void put(IpPort ipPort, String uri, RequestParam requestParam, Handler<RestResponse> responseHandler) {
         Holder<HttpClientResponse> holder = Deencapsulation.getField(responseHandler, "arg$4");
@@ -571,7 +560,7 @@ public class TestServiceRegistryClientImpl {
         return 400;
       }
     }.getMockInstance();
-    new MockUp<RestUtils>() {
+    new MockUp<RestClientUtil>() {
       @Mock
       void put(IpPort ipPort, String uri, RequestParam requestParam, Handler<RestResponse> responseHandler) {
         Holder<HttpClientResponse> holder = Deencapsulation.getField(responseHandler, "arg$4");


[servicecomb-java-chassis] 15/19: [SCB-1691] add schema and endpoint into all ServiceRegistry instances

Posted by ya...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

yaohaishi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit d2126d3f68c2414287d4462c372b903b0237141d
Author: yhs0092 <yh...@163.com>
AuthorDate: Sun Feb 16 21:32:44 2020 +0800

    [SCB-1691] add schema and endpoint into all ServiceRegistry instances
---
 .../servicecomb/core/provider/producer/ProducerBootListener.java | 9 +++++++--
 .../org/apache/servicecomb/core/transport/TransportManager.java  | 7 +++++--
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerBootListener.java b/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerBootListener.java
index aec2e33..4b85909 100644
--- a/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerBootListener.java
+++ b/core/src/main/java/org/apache/servicecomb/core/provider/producer/ProducerBootListener.java
@@ -28,6 +28,7 @@ import org.apache.servicecomb.core.definition.MicroserviceMeta;
 import org.apache.servicecomb.core.definition.OperationMeta;
 import org.apache.servicecomb.core.definition.SchemaMeta;
 import org.apache.servicecomb.foundation.common.utils.IOUtils;
+import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.api.Const;
 import org.apache.servicecomb.serviceregistry.api.registry.BasePath;
 import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
@@ -65,10 +66,14 @@ public class ProducerBootListener implements BootListener {
           microserviceMeta.getMicroserviceName(),
           schemaMeta.getSchemaId(),
           content);
-      microservice.addSchema(schemaMeta.getSchemaId(), content);
+      RegistryUtils.executeOnEachServiceRegistry(sr -> {
+        sr.getMicroservice().addSchema(schemaMeta.getSchemaId(), content);
+      });
     }
 
-    saveBasePaths(microserviceMeta, microservice);
+    RegistryUtils.executeOnEachServiceRegistry(sr -> {
+      saveBasePaths(microserviceMeta, sr.getMicroservice());
+    });
   }
 
   // just compatible to old 3rd components, servicecomb not use it......
diff --git a/core/src/main/java/org/apache/servicecomb/core/transport/TransportManager.java b/core/src/main/java/org/apache/servicecomb/core/transport/TransportManager.java
index 2e02279..a52c93b 100644
--- a/core/src/main/java/org/apache/servicecomb/core/transport/TransportManager.java
+++ b/core/src/main/java/org/apache/servicecomb/core/transport/TransportManager.java
@@ -29,6 +29,7 @@ import org.apache.servicecomb.core.SCBEngine;
 import org.apache.servicecomb.core.Transport;
 import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException;
 import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
+import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -60,8 +61,10 @@ public class TransportManager {
         Endpoint endpoint = transport.getPublishEndpoint();
         if (endpoint != null && endpoint.getEndpoint() != null) {
           LOGGER.info("endpoint to publish: {}", endpoint.getEndpoint());
-          Microservice microservice = scbEngine.getServiceRegistry().getMicroservice();
-          microservice.getInstance().getEndpoints().add(endpoint.getEndpoint());
+          RegistryUtils.executeOnEachServiceRegistry(sr -> {
+            Microservice microservice = sr.getMicroservice();
+            microservice.getInstance().getEndpoints().add(endpoint.getEndpoint());
+          });
         }
         continue;
       }


[servicecomb-java-chassis] 06/19: [SCB-1691] add RestClientUtil for multiple ServiceRegistryClient instance situation

Posted by ya...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

yaohaishi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit 096a43b6a6412caf5836ecdb88fb2caf1c1e5c73
Author: yhs0092 <yh...@163.com>
AuthorDate: Wed Jan 15 09:22:59 2020 +0800

    [SCB-1691] add RestClientUtil for multiple ServiceRegistryClient instance situation
    
    the legacy RestUtils is preserved for compatibility and marked deprecated
---
 .../http/{RestUtils.java => RestClientUtil.java}   | 51 +++++++++++++---------
 .../serviceregistry/client/http/RestUtils.java     |  5 +++
 .../config/ServiceRegistryConfig.java              | 14 ++++++
 .../config/ServiceRegistryConfigBuilder.java       |  9 +++-
 4 files changed, 57 insertions(+), 22 deletions(-)

diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestUtils.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestClientUtil.java
similarity index 81%
copy from service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestUtils.java
copy to service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestClientUtil.java
index 42d1e03..568ab57 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestUtils.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestClientUtil.java
@@ -22,8 +22,8 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.UnknownHostException;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
-import java.util.ServiceLoader;
 
 import org.apache.servicecomb.foundation.auth.AuthHeaderProvider;
 import org.apache.servicecomb.foundation.auth.SignRequest;
@@ -40,8 +40,8 @@ import io.vertx.core.http.CaseInsensitiveHeaders;
 import io.vertx.core.http.HttpClientRequest;
 import io.vertx.core.http.HttpMethod;
 
-final class RestUtils {
-  private static final Logger LOGGER = LoggerFactory.getLogger(RestUtils.class);
+final class RestClientUtil {
+  private static final Logger LOGGER = LoggerFactory.getLogger(RestClientUtil.class);
 
   private static final String HEADER_CONTENT_TYPE = "Content-Type";
 
@@ -49,22 +49,31 @@ final class RestUtils {
 
   private static final String HEADER_TENANT_NAME = "x-domain-name";
 
-  private static final ServiceLoader<AuthHeaderProvider> authHeaderProviders =
-      ServiceLoader.load(AuthHeaderProvider.class);
+  private List<AuthHeaderProvider> authHeaderProviders;
 
-  private RestUtils() {
+  private int requestTimeout;
+
+  private String tenantName;
+
+  private HttpClientPool httpClientPool;
+
+  RestClientUtil(ServiceRegistryConfig serviceRegistryConfig) {
+    this.authHeaderProviders = serviceRegistryConfig.getAuthHeaderProviders();
+    this.requestTimeout = serviceRegistryConfig.getRequestTimeout();
+    this.tenantName = serviceRegistryConfig.getTenantName();
+    this.httpClientPool = new HttpClientPool(serviceRegistryConfig);
   }
 
-  public static void httpDo(RequestContext requestContext, Handler<RestResponse> responseHandler) {
+  public void httpDo(RequestContext requestContext, Handler<RestResponse> responseHandler) {
     if (requestContext.getParams().getTimeout() != 0) {
       httpDo(requestContext.getParams().getTimeout(), requestContext, responseHandler);
       return;
     }
-    httpDo(ServiceRegistryConfig.INSTANCE.getRequestTimeout(), requestContext, responseHandler);
+    httpDo(requestTimeout, requestContext, responseHandler);
   }
 
-  public static void httpDo(long timeout, RequestContext requestContext, Handler<RestResponse> responseHandler) {
-    HttpClientWithContext vertxHttpClient = HttpClientPool.INSTANCE.getClient();
+  public void httpDo(long timeout, RequestContext requestContext, Handler<RestResponse> responseHandler) {
+    HttpClientWithContext vertxHttpClient = httpClientPool.getClient();
     vertxHttpClient.runOnContext(httpClient -> {
       IpPort ipPort = requestContext.getIpPort();
       HttpMethod httpMethod = requestContext.getMethod();
@@ -146,7 +155,7 @@ final class RestUtils {
     });
   }
 
-  public static RequestContext createRequestContext(HttpMethod method, IpPort ipPort, String uri,
+  public RequestContext createRequestContext(HttpMethod method, IpPort ipPort, String uri,
       RequestParam requestParam) {
     RequestContext requestContext = new RequestContext();
     requestContext.setMethod(method);
@@ -156,7 +165,7 @@ final class RestUtils {
     return requestContext;
   }
 
-  public static SignRequest createSignRequest(String method, IpPort ipPort, RequestParam requestParam, String url,
+  public SignRequest createSignRequest(String method, IpPort ipPort, RequestParam requestParam, String url,
       Map<String, String> headers) {
     SignRequest signReq = new SignRequest();
     StringBuilder endpoint = new StringBuilder("https://" + ipPort.getHostOrIp());
@@ -176,44 +185,44 @@ final class RestUtils {
     return signReq;
   }
 
-  public static void addDefaultHeaders(HttpClientRequest request) {
+  public void addDefaultHeaders(HttpClientRequest request) {
     request.headers().addAll(getDefaultHeaders());
   }
 
-  private static Map<String, String> defaultHeaders() {
+  private Map<String, String> defaultHeaders() {
     Map<String, String> headers = new HashMap<>();
     headers.put(HEADER_CONTENT_TYPE, "application/json");
     headers.put(HEADER_USER_AGENT, "cse-serviceregistry-client/1.0.0");
-    headers.put(HEADER_TENANT_NAME, ServiceRegistryConfig.INSTANCE.getTenantName());
+    headers.put(HEADER_TENANT_NAME, tenantName);
 
     return headers;
   }
 
-  public static MultiMap getDefaultHeaders() {
+  public MultiMap getDefaultHeaders() {
     return new CaseInsensitiveHeaders().addAll(defaultHeaders());
   }
 
-  public static void get(IpPort ipPort, String uri, RequestParam requestParam,
+  public void get(IpPort ipPort, String uri, RequestParam requestParam,
       Handler<RestResponse> responseHandler) {
     httpDo(createRequestContext(HttpMethod.GET, ipPort, uri, requestParam), responseHandler);
   }
 
-  public static void post(IpPort ipPort, String uri, RequestParam requestParam,
+  public void post(IpPort ipPort, String uri, RequestParam requestParam,
       Handler<RestResponse> responseHandler) {
     httpDo(createRequestContext(HttpMethod.POST, ipPort, uri, requestParam), responseHandler);
   }
 
-  public static void put(IpPort ipPort, String uri, RequestParam requestParam,
+  public void put(IpPort ipPort, String uri, RequestParam requestParam,
       Handler<RestResponse> responseHandler) {
     httpDo(createRequestContext(HttpMethod.PUT, ipPort, uri, requestParam), responseHandler);
   }
 
-  public static void delete(IpPort ipPort, String uri, RequestParam requestParam,
+  public void delete(IpPort ipPort, String uri, RequestParam requestParam,
       Handler<RestResponse> responseHandler) {
     httpDo(createRequestContext(HttpMethod.DELETE, ipPort, uri, requestParam), responseHandler);
   }
 
-  public static Map<String, String> getSignAuthHeaders(SignRequest signReq) {
+  public Map<String, String> getSignAuthHeaders(SignRequest signReq) {
     Map<String, String> headers = new HashMap<>();
     authHeaderProviders.forEach(provider -> headers.putAll(provider.getSignAuthHeaders(signReq)));
     return headers;
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestUtils.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestUtils.java
index 42d1e03..b902611 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestUtils.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/RestUtils.java
@@ -40,6 +40,11 @@ import io.vertx.core.http.CaseInsensitiveHeaders;
 import io.vertx.core.http.HttpClientRequest;
 import io.vertx.core.http.HttpMethod;
 
+/**
+ * This class is designed following singleton pattern, but it's not suitable for multi sc cluster occasion.
+ * @deprecated consider to use {@link RestClientUtil} instead.
+ */
+@Deprecated
 final class RestUtils {
   private static final Logger LOGGER = LoggerFactory.getLogger(RestUtils.class);
 
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
index 1596077..d16d485 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
@@ -18,7 +18,9 @@
 package org.apache.servicecomb.serviceregistry.config;
 
 import java.util.ArrayList;
+import java.util.List;
 
+import org.apache.servicecomb.foundation.auth.AuthHeaderProvider;
 import org.apache.servicecomb.foundation.common.net.IpPort;
 import org.apache.servicecomb.serviceregistry.ServiceRegistry;
 
@@ -139,6 +141,8 @@ public final class ServiceRegistryConfig {
 
   private String proxyPasswd;
 
+  private List<AuthHeaderProvider> authHeaderProviders;
+
   /**
    * Read the service registry related configurations and build the {@link ServiceRegistryConfig}
    * object. Since most of the service registry configurations are similar, this method may be
@@ -412,4 +416,14 @@ public final class ServiceRegistryConfig {
     this.proxyPasswd = proxyPasswd;
     return this;
   }
+
+  public List<AuthHeaderProvider> getAuthHeaderProviders() {
+    return authHeaderProviders;
+  }
+
+  public ServiceRegistryConfig setAuthHeaderProviders(
+      List<AuthHeaderProvider> authHeaderProviders) {
+    this.authHeaderProviders = authHeaderProviders;
+    return this;
+  }
 }
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfigBuilder.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfigBuilder.java
index 95f2b6c..1651532 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfigBuilder.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfigBuilder.java
@@ -25,8 +25,10 @@ import java.util.Objects;
 import org.apache.servicecomb.config.ConfigUtil;
 import org.apache.servicecomb.deployment.Deployment;
 import org.apache.servicecomb.deployment.DeploymentProvider;
+import org.apache.servicecomb.foundation.auth.AuthHeaderProvider;
 import org.apache.servicecomb.foundation.common.net.IpPort;
 import org.apache.servicecomb.foundation.common.net.NetUtils;
+import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -76,7 +78,8 @@ class ServiceRegistryConfigBuilder {
         .setProxyHost(getProxyHost())
         .setProxyPort(getProxyPort())
         .setProxyUsername(getProxyUsername())
-        .setProxyPasswd(getProxyPasswd());
+        .setProxyPasswd(getProxyPasswd())
+        .setAuthHeaderProviders(getAuthHeaderProviders());
   }
 
   public HttpVersion getHttpVersion() {
@@ -292,6 +295,10 @@ class ServiceRegistryConfigBuilder {
     return getProperty(null, ServiceRegistryConfig.PROXY_PASSWD);
   }
 
+  public List<AuthHeaderProvider> getAuthHeaderProviders() {
+    return SPIServiceUtils.getAllService(AuthHeaderProvider.class);
+  }
+
   private String getProperty(String defaultValue, String... keys) {
     String property = null;
     for (String key : keys) {


[servicecomb-java-chassis] 10/19: [SCB-1691] ServiceRegistry use serviceRegistryCache

Posted by ya...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

yaohaishi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit d4e8db6970c4a8e5b383c0b9ebc114118497757e
Author: yhs0092 <yh...@163.com>
AuthorDate: Sat Feb 15 19:07:07 2020 +0800

    [SCB-1691] ServiceRegistry use serviceRegistryCache
---
 .../servicecomb/serviceregistry/RegistryUtils.java | 33 +++++++++
 .../consumer/MicroserviceVersions.java             |  2 +-
 .../registry/AbstractServiceRegistry.java          | 80 ++++++++++------------
 .../registry/RemoteServiceRegistry.java            |  5 +-
 .../serviceregistry/RegistryUtilsTest.java         | 77 +++++++++++++++++++++
 5 files changed, 151 insertions(+), 46 deletions(-)

diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
index 46de489..2f93bd6 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
@@ -20,6 +20,7 @@ package org.apache.servicecomb.serviceregistry;
 import java.net.InetSocketAddress;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -33,6 +34,7 @@ import org.apache.servicecomb.foundation.common.net.IpPort;
 import org.apache.servicecomb.foundation.common.net.NetUtils;
 import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+import org.apache.servicecomb.serviceregistry.api.response.FindInstancesResponse;
 import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager;
 import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManagerNew;
 import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient;
@@ -41,6 +43,7 @@ import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
 import org.apache.servicecomb.serviceregistry.consumer.AppManager;
 import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition;
 import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryFactory;
+import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache;
 import org.apache.servicecomb.serviceregistry.swagger.SwaggerLoader;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -250,6 +253,36 @@ public final class RegistryUtils {
     return serviceRegistry.findServiceInstances(appId, serviceName, versionRule, revision);
   }
 
+  /**
+   * for compatibility
+   */
+  public static MicroserviceInstances convertCacheToMicroserviceInstances(MicroserviceCache microserviceCache) {
+    MicroserviceInstances microserviceInstances = new MicroserviceInstances();
+    switch (microserviceCache.getStatus()) {
+      case SERVICE_NOT_FOUND:
+        microserviceInstances.setMicroserviceNotExist(true);
+        microserviceInstances.setNeedRefresh(false);
+        microserviceInstances.setRevision("");
+        microserviceInstances.setInstancesResponse(null);
+        return microserviceInstances;
+      case NO_CHANGE:
+        microserviceInstances.setMicroserviceNotExist(false);
+        microserviceInstances.setNeedRefresh(false);
+        microserviceInstances.setRevision(microserviceCache.getRevisionId());
+        return microserviceInstances;
+      case REFRESHED:
+        microserviceInstances.setMicroserviceNotExist(false);
+        microserviceInstances.setNeedRefresh(true);
+        microserviceInstances.setRevision(microserviceCache.getRevisionId());
+        FindInstancesResponse findInstancesResponse = new FindInstancesResponse();
+        findInstancesResponse.setInstances(new ArrayList<>(microserviceCache.getInstances()));
+        microserviceInstances.setInstancesResponse(findInstancesResponse);
+        return microserviceInstances;
+      default:
+        return null;
+    }
+  }
+
   public static String calcSchemaSummary(String schemaContent) {
     return Hashing.sha256().newHasher().putString(schemaContent, Charsets.UTF_8).hash().toString();
   }
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java
index 8802a15..5dc1cec 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java
@@ -166,7 +166,7 @@ public class MicroserviceVersions {
       return;
     }
 
-    if (!microserviceInstances.isNeedRefresh()) {
+    if (null != revision && revision.equals(microserviceInstances.getRevision())) {
       return;
     }
 
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java
index a37fdbc..214968a 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java
@@ -27,6 +27,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
 
+import org.apache.servicecomb.foundation.common.concurrency.SuppressedRunnableWrapper;
 import org.apache.servicecomb.serviceregistry.Features;
 import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.ServiceRegistry;
@@ -48,6 +49,9 @@ import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition;
 import org.apache.servicecomb.serviceregistry.definition.MicroserviceNameParser;
 import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache;
 import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCacheKey;
+import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCacheRefreshedEvent;
+import org.apache.servicecomb.serviceregistry.registry.cache.RefreshableServiceRegistryCache;
+import org.apache.servicecomb.serviceregistry.registry.cache.ServiceRegistryCache;
 import org.apache.servicecomb.serviceregistry.task.MicroserviceServiceCenterTask;
 import org.apache.servicecomb.serviceregistry.task.ServiceCenterTask;
 import org.apache.servicecomb.serviceregistry.task.event.RecoveryEvent;
@@ -85,6 +89,8 @@ public abstract class AbstractServiceRegistry implements ServiceRegistry {
 
   private String name;
 
+  RefreshableServiceRegistryCache serviceRegistryCache;
+
   public AbstractServiceRegistry(EventBus eventBus, ServiceRegistryConfig serviceRegistryConfig,
       MicroserviceDefinition microserviceDefinition) {
     setName(serviceRegistryConfig.getRegistryName());
@@ -104,6 +110,14 @@ public abstract class AbstractServiceRegistry implements ServiceRegistry {
     createServiceCenterTask();
 
     eventBus.register(this);
+
+    initCache();
+  }
+
+  private void initCache() {
+    serviceRegistryCache = new RefreshableServiceRegistryCache(microservice, srClient);
+    serviceRegistryCache.setCacheRefreshedWatcher(
+        caches -> eventBus.post(new MicroserviceCacheRefreshedEvent(caches)));
   }
 
   @Override
@@ -207,50 +221,15 @@ public abstract class AbstractServiceRegistry implements ServiceRegistry {
 
   public MicroserviceInstances findServiceInstances(String appId, String serviceName,
       String versionRule, String revision) {
-    MicroserviceInstances microserviceInstances = srClient.findServiceInstances(microservice.getServiceId(),
-        appId,
-        serviceName,
-        versionRule,
-        revision);
-
-    if (microserviceInstances == null) {
-      LOGGER.error("Can not find any instances from service center due to previous errors. service={}/{}/{}",
-          appId,
-          serviceName,
-          versionRule);
-      return null;
-    }
-
-    if (microserviceInstances.isMicroserviceNotExist()) {
-      return microserviceInstances;
-    }
-
-    if (!microserviceInstances.isNeedRefresh()) {
-      LOGGER.debug("instances revision is not changed, service={}/{}/{}", appId, serviceName, versionRule);
-      return microserviceInstances;
-    }
-
-    List<MicroserviceInstance> instances = microserviceInstances.getInstancesResponse().getInstances();
-    LOGGER.info("find instances[{}] from service center success. service={}/{}/{}, old revision={}, new revision={}",
-        instances.size(),
-        appId,
-        serviceName,
-        versionRule,
-        revision,
-        microserviceInstances.getRevision());
-    for (MicroserviceInstance instance : instances) {
-      LOGGER.info("service id={}, instance id={}, endpoints={}",
-          instance.getServiceId(),
-          instance.getInstanceId(),
-          instance.getEndpoints());
-    }
-    return microserviceInstances;
+    MicroserviceCache microserviceCache = serviceRegistryCache
+        .findServiceCache(MicroserviceCacheKey.builder()
+            .serviceName(serviceName).appId(appId).env(microservice.getEnvironment()).build());
+    return RegistryUtils.convertCacheToMicroserviceInstances(microserviceCache);
   }
 
   @Override
   public MicroserviceCache findMicroserviceCache(MicroserviceCacheKey microserviceCacheKey) {
-    // TODO find MicroserviceCache from ServiceRegistryCache
-    return null;
+    return serviceRegistryCache.findServiceCache(microserviceCacheKey);
   }
 
   @Override
@@ -333,6 +312,10 @@ public abstract class AbstractServiceRegistry implements ServiceRegistry {
     this.name = name;
   }
 
+  public ServiceRegistryCache getServiceRegistryCache() {
+    return serviceRegistryCache;
+  }
+
   @Subscribe
   public void onShutdown(ShutdownEvent event) {
     LOGGER.info("service center task is shutdown.");
@@ -342,17 +325,28 @@ public abstract class AbstractServiceRegistry implements ServiceRegistry {
   // post from watch eventloop, should refresh the exact microservice instances immediately
   @Subscribe
   public void onMicroserviceInstanceChanged(MicroserviceInstanceChangedEvent changedEvent) {
-    executorService.execute(() -> RegistryUtils.getAppManager().onMicroserviceInstanceChanged(changedEvent));
+    executorService.execute(new SuppressedRunnableWrapper(
+        () -> {
+          serviceRegistryCache.onMicroserviceInstanceChanged(changedEvent);
+          RegistryUtils.getAppManager().onMicroserviceInstanceChanged(changedEvent);
+        }));
   }
 
   // post from watch eventloop, should refresh all instances immediately
   @Subscribe
   public void serviceRegistryRecovery(RecoveryEvent event) {
-    executorService.execute(RegistryUtils.getAppManager()::pullInstances);
+    executorService.execute(() -> {
+      serviceRegistryCache.forceRefreshCache();
+      RegistryUtils.getAppManager().pullInstances();
+    });
   }
 
   @Subscribe
   public void onSafeModeChanged(SafeModeChangeEvent modeChangeEvent) {
-    executorService.execute(() -> RegistryUtils.getAppManager().onSafeModeChanged(modeChangeEvent));
+    executorService.execute(() -> {
+      LOGGER.warn("receive SafeModeChangeEvent, current mode={}", modeChangeEvent.getCurrentMode());
+      serviceRegistryCache.onSafeModeChanged(modeChangeEvent);
+      RegistryUtils.getAppManager().onSafeModeChanged(modeChangeEvent);
+    });
   }
 }
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java
index b6af226..2002177 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java
@@ -23,7 +23,6 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.servicecomb.foundation.common.concurrency.SuppressedRunnableWrapper;
 import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
-import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient;
 import org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl;
 import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
@@ -85,7 +84,9 @@ public class RemoteServiceRegistry extends AbstractServiceRegistry {
         TimeUnit.SECONDS);
 
     taskPool.scheduleAtFixedRate(
-        new SuppressedRunnableWrapper(RegistryUtils.getAppManager()::pullInstances),
+        new SuppressedRunnableWrapper(() -> {
+          serviceRegistryCache.refreshCache();
+        }),
         serviceRegistryConfig.getInstancePullInterval(),
         serviceRegistryConfig.getInstancePullInterval(),
         TimeUnit.SECONDS);
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/RegistryUtilsTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/RegistryUtilsTest.java
new file mode 100644
index 0000000..ab7efc5
--- /dev/null
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/RegistryUtilsTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.serviceregistry;
+
+import java.util.Collections;
+
+import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances;
+import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache.MicroserviceCacheStatus;
+import org.apache.servicecomb.serviceregistry.registry.cache.MockedMicroserviceCache;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class RegistryUtilsTest {
+  @Test
+  public void convertCacheToMicroserviceInstances() {
+    MockedMicroserviceCache microserviceCache = new MockedMicroserviceCache();
+    microserviceCache.setStatus(MicroserviceCacheStatus.CLIENT_ERROR);
+    MicroserviceInstances microserviceInstances = RegistryUtils
+        .convertCacheToMicroserviceInstances(microserviceCache);
+    Assert.assertNull(microserviceInstances);
+
+    microserviceCache = new MockedMicroserviceCache();
+    microserviceCache.setStatus(MicroserviceCacheStatus.SETTING_CACHE_ERROR);
+    microserviceInstances = RegistryUtils.convertCacheToMicroserviceInstances(microserviceCache);
+    Assert.assertNull(microserviceInstances);
+
+    microserviceCache = new MockedMicroserviceCache();
+    microserviceCache.setStatus(MicroserviceCacheStatus.INIT);
+    microserviceInstances = RegistryUtils.convertCacheToMicroserviceInstances(microserviceCache);
+    Assert.assertNull(microserviceInstances);
+
+    microserviceCache = new MockedMicroserviceCache();
+    microserviceCache.setStatus(MicroserviceCacheStatus.SERVICE_NOT_FOUND);
+    microserviceInstances = RegistryUtils.convertCacheToMicroserviceInstances(microserviceCache);
+    Assert.assertTrue(microserviceInstances.isMicroserviceNotExist());
+    Assert.assertFalse(microserviceInstances.isNeedRefresh());
+    Assert.assertEquals("", microserviceInstances.getRevision());
+    Assert.assertNull(microserviceInstances.getInstancesResponse());
+
+    microserviceCache = new MockedMicroserviceCache();
+    microserviceCache.setStatus(MicroserviceCacheStatus.REFRESHED);
+    microserviceCache.setRevisionId("0166f3c18702617d5e55cf911e4e412cc8760dab");
+    MicroserviceInstance microserviceInstance = new MicroserviceInstance();
+    microserviceCache.setInstances(Collections.singletonList(microserviceInstance));
+    microserviceInstances = RegistryUtils.convertCacheToMicroserviceInstances(microserviceCache);
+    Assert.assertFalse(microserviceInstances.isMicroserviceNotExist());
+    Assert.assertTrue(microserviceInstances.isNeedRefresh());
+    Assert.assertEquals("0166f3c18702617d5e55cf911e4e412cc8760dab", microserviceInstances.getRevision());
+    Assert.assertEquals(1, microserviceInstances.getInstancesResponse().getInstances().size());
+    Assert.assertSame(microserviceInstance, microserviceInstances.getInstancesResponse().getInstances().get(0));
+
+    microserviceCache = new MockedMicroserviceCache();
+    microserviceCache.setStatus(MicroserviceCacheStatus.NO_CHANGE);
+    microserviceCache.setRevisionId("0166f3c18702617d5e55cf911e4e412cc8760dab");
+    microserviceInstances = RegistryUtils.convertCacheToMicroserviceInstances(microserviceCache);
+    Assert.assertFalse(microserviceInstances.isMicroserviceNotExist());
+    Assert.assertFalse(microserviceInstances.isNeedRefresh());
+    Assert.assertEquals("0166f3c18702617d5e55cf911e4e412cc8760dab", microserviceInstances.getRevision());
+    Assert.assertNull(microserviceInstances.getInstancesResponse());
+  }
+}
\ No newline at end of file


[servicecomb-java-chassis] 02/19: [SCB-1691] Decouple the ServiceRegistry and other modules

Posted by ya...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

yaohaishi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit d6cbf86cc4d3b9d854456a393fd3c2965e43eb17
Author: yhs0092 <yh...@163.com>
AuthorDate: Wed Feb 5 15:23:57 2020 +0800

    [SCB-1691] Decouple the ServiceRegistry and other modules
    
    - DiscoveryTree get InstanceCacheManager from RegistryUtils directly
    - SwaggerLoader don't rely on ServiceRegistry directly
    - AppManager does not refer to ServiceRegistry directly
    - ServiceRegistry does not hold AppManager
    - ServiceRegistry does not hold InstanceCacheManager
    - ServiceRegistryFactory doesn't hold the instance of ServiceRegistry
    - SCBEngine doesn't hold ServiceRegistry instance directly
---
 .../org/apache/servicecomb/core/SCBEngine.java     | 22 +++++-------
 .../consumer/MicroserviceReferenceConfig.java      |  2 +-
 .../handler/impl/TestSimpleLoadBalanceHandler.java |  5 +--
 .../servicecomb/demo/edge/consumer/Consumer.java   |  2 +-
 .../jaxrs/client/MultiErrorCodeServiceClient.java  |  2 +-
 .../loadbalance/TestLoadBalanceHandler2.java       | 21 +++++++----
 .../loadbalance/TestLoadbalanceHandler.java        |  3 +-
 .../java/org/apache/servicecomb/it/ITUtils.java    |  4 +--
 .../servicecomb/it/deploy/MicroserviceDeploy.java  |  2 +-
 .../it/extend/engine/GateRestTemplate.java         |  2 +-
 .../it/extend/engine/ITSCBAsyncRestTemplate.java   |  4 +--
 .../it/extend/engine/ITSCBRestTemplate.java        |  2 +-
 .../servicecomb/it/edge/PreLoadBootListener.java   |  2 +-
 .../async/CseAsyncClientHttpRequestTest.java       |  7 +++-
 .../servicecomb/serviceregistry/RegistryUtils.java | 33 ++++++++++++++---
 .../serviceregistry/ServiceRegistry.java           | 20 +++++------
 .../serviceregistry/consumer/AppManager.java       | 14 ++------
 .../consumer/MicroserviceVersion.java              |  6 ++--
 .../consumer/MicroserviceVersions.java             |  5 +--
 .../consumer/StaticMicroserviceVersions.java       |  5 +--
 .../diagnosis/instance/InstanceCacheCheckTask.java |  3 +-
 .../serviceregistry/discovery/DiscoveryTree.java   |  1 -
 .../registry/AbstractServiceRegistry.java          | 42 +++++-----------------
 .../registry/RemoteServiceRegistry.java            |  3 +-
 .../registry/ServiceRegistryFactory.java           | 20 -----------
 .../serviceregistry/swagger/SwaggerLoader.java     | 17 ++++-----
 .../serviceregistry/MockMicroserviceVersions.java  |  9 ++---
 .../servicecomb/serviceregistry/TestConsumers.java |  4 +--
 .../servicecomb/serviceregistry/TestRegistry.java  |  1 -
 .../serviceregistry/TestRegistryBase.java          | 14 ++++----
 .../instance/TestInstanceCacheChecker.java         | 18 ++++++----
 .../discovery/TestDiscoveryTree.java               | 17 +++------
 .../registry/TestServiceRegistryFactory.java       |  8 ++---
 .../serviceregistry/swagger/TestSwaggerLoader.java | 35 +++++++++---------
 34 files changed, 166 insertions(+), 189 deletions(-)

diff --git a/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java b/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java
index 915610b..e704efe 100644
--- a/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java
+++ b/core/src/main/java/org/apache/servicecomb/core/SCBEngine.java
@@ -103,8 +103,6 @@ public class SCBEngine {
 
   private volatile SCBStatus status = SCBStatus.DOWN;
 
-  private ServiceRegistry serviceRegistry;
-
   private EventBus eventBus;
 
   private ExecutorManager executorManager = new ExecutorManager();
@@ -123,8 +121,7 @@ public class SCBEngine {
   private Thread shutdownHook;
 
   protected SCBEngine() {
-    serviceRegistry = RegistryUtils.getServiceRegistry();
-    eventBus = serviceRegistry.getEventBus();
+    eventBus = EventManager.getEventBus();
 
     // see SCB-1266, fix Log4j2 leak marker problem
     LogMarkerLeakFixUtils.fix();
@@ -142,7 +139,7 @@ public class SCBEngine {
   }
 
   public String getAppId() {
-    return serviceRegistry.getAppId();
+    return RegistryUtils.getAppId();
   }
 
   public void setStatus(SCBStatus status) {
@@ -165,11 +162,11 @@ public class SCBEngine {
   }
 
   public ServiceRegistry getServiceRegistry() {
-    return serviceRegistry;
+    return RegistryUtils.getServiceRegistry();
   }
 
   public SwaggerLoader getSwaggerLoader() {
-    return serviceRegistry.getSwaggerLoader();
+    return RegistryUtils.getSwaggerLoader();
   }
 
   public ConsumerHandlerManager getConsumerHandlerManager() {
@@ -324,13 +321,12 @@ public class SCBEngine {
     LOGGER.info(serviceInfo.toString());
   }
 
-
   private void doRun() throws Exception {
     status = SCBStatus.STARTING;
 
     bootListeners.sort(Comparator.comparingInt(BootListener::getOrder));
 
-    AbstractEndpointsCache.init(serviceRegistry.getInstanceCacheManager(), transportManager);
+    AbstractEndpointsCache.init(RegistryUtils.getInstanceCacheManager(), transportManager);
 
     triggerEvent(EventType.BEFORE_HANDLER);
     HandlerConfigUtils.init(consumerHandlerManager, producerHandlerManager);
@@ -354,14 +350,14 @@ public class SCBEngine {
 
     triggerAfterRegistryEvent();
 
-    serviceRegistry.run();
+    RegistryUtils.run();
 
     shutdownHook = new Thread(this::destroyForShutdownHook);
     Runtime.getRuntime().addShutdownHook(shutdownHook);
   }
 
   private void createProducerMicroserviceMeta() {
-    String microserviceName = serviceRegistry.getMicroservice().getServiceName();
+    String microserviceName = RegistryUtils.getMicroservice().getServiceName();
     List<Handler> consumerHandlerChain = consumerHandlerManager.getOrCreate(microserviceName);
     List<Handler> producerHandlerChain = producerHandlerManager.getOrCreate(microserviceName);
 
@@ -399,7 +395,7 @@ public class SCBEngine {
 
     //Step 3: Unregister microservice instance from Service Center and close vertx
     // Forbidden other consumers find me
-    serviceRegistry.destroy();
+    RegistryUtils.destroy();
     VertxUtils.blockCloseVertxByName("registry");
     serviceRegistryListener.destroy();
 
@@ -464,7 +460,7 @@ public class SCBEngine {
    * @return
    */
   public MicroserviceReferenceConfig createMicroserviceReferenceConfig(String microserviceName, String versionRule) {
-    MicroserviceVersions microserviceVersions = serviceRegistry.getAppManager()
+    MicroserviceVersions microserviceVersions = RegistryUtils.getAppManager()
         .getOrCreateMicroserviceVersions(parseAppId(microserviceName), microserviceName);
     ConsumerMicroserviceVersionsMeta microserviceVersionsMeta = CoreMetaUtils
         .getMicroserviceVersionsMeta(microserviceVersions);
diff --git a/core/src/main/java/org/apache/servicecomb/core/provider/consumer/MicroserviceReferenceConfig.java b/core/src/main/java/org/apache/servicecomb/core/provider/consumer/MicroserviceReferenceConfig.java
index d6f5740..feaf882 100644
--- a/core/src/main/java/org/apache/servicecomb/core/provider/consumer/MicroserviceReferenceConfig.java
+++ b/core/src/main/java/org/apache/servicecomb/core/provider/consumer/MicroserviceReferenceConfig.java
@@ -100,7 +100,7 @@ public class MicroserviceReferenceConfig {
   }
 
   private void mark3rdPartyService(OperationMeta operationMeta, ReferenceConfig referenceConfig) {
-    final MicroserviceVersions microserviceVersions = RegistryUtils.getServiceRegistry().getAppManager()
+    final MicroserviceVersions microserviceVersions = RegistryUtils.getAppManager()
         .getOrCreateMicroserviceVersions(
             operationMeta.getMicroserviceMeta().getAppId(),
             operationMeta.getMicroserviceName());
diff --git a/core/src/test/java/org/apache/servicecomb/core/handler/impl/TestSimpleLoadBalanceHandler.java b/core/src/test/java/org/apache/servicecomb/core/handler/impl/TestSimpleLoadBalanceHandler.java
index fc4545a..3f6c708 100644
--- a/core/src/test/java/org/apache/servicecomb/core/handler/impl/TestSimpleLoadBalanceHandler.java
+++ b/core/src/test/java/org/apache/servicecomb/core/handler/impl/TestSimpleLoadBalanceHandler.java
@@ -27,6 +27,7 @@ import org.apache.servicecomb.core.Transport;
 import org.apache.servicecomb.core.bootstrap.SCBBootstrap;
 import org.apache.servicecomb.foundation.common.cache.VersionedCache;
 import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
+import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
 import org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter;
 import org.apache.servicecomb.swagger.invocation.AsyncResponse;
@@ -67,9 +68,9 @@ public class TestSimpleLoadBalanceHandler {
       }
     };
 
-    new Expectations(scbEngine.getServiceRegistry().getInstanceCacheManager()) {
+    new Expectations(RegistryUtils.getInstanceCacheManager()) {
       {
-        scbEngine.getServiceRegistry().getInstanceCacheManager()
+        RegistryUtils.getInstanceCacheManager()
             .getOrCreateVersionedCache(anyString, anyString, anyString);
         result = instanceVersionedCache;
       }
diff --git a/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/Consumer.java b/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/Consumer.java
index 7117f07..7d5d567 100644
--- a/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/Consumer.java
+++ b/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/Consumer.java
@@ -264,7 +264,7 @@ public class Consumer {
 
   private URIEndpointObject prepareEdge(String prefix) {
     Microservice microservice = RegistryUtils.getMicroservice();
-    MicroserviceInstance microserviceInstance = (MicroserviceInstance) RegistryUtils.getServiceRegistry()
+    MicroserviceInstance microserviceInstance = (MicroserviceInstance) RegistryUtils
         .getAppManager()
         .getOrCreateMicroserviceVersionRule(microservice.getAppId(), "edge", DefinitionConst.VERSION_RULE_ALL)
         .getVersionedCache()
diff --git a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/MultiErrorCodeServiceClient.java b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/MultiErrorCodeServiceClient.java
index a58cbc5..3a7ec70 100644
--- a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/MultiErrorCodeServiceClient.java
+++ b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/MultiErrorCodeServiceClient.java
@@ -78,7 +78,7 @@ public class MultiErrorCodeServiceClient implements CategorizedTestCase {
 
   private static void prepareServerDirectURL() {
     Microservice microservice = RegistryUtils.getMicroservice();
-    MicroserviceInstance microserviceInstance = (MicroserviceInstance) RegistryUtils.getServiceRegistry()
+    MicroserviceInstance microserviceInstance = (MicroserviceInstance) RegistryUtils
         .getAppManager()
         .getOrCreateMicroserviceVersionRule(microservice.getAppId(), "jaxrs", DefinitionConst.VERSION_RULE_ALL)
         .getVersionedCache()
diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceHandler2.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceHandler2.java
index e340577..2edc5bd 100644
--- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceHandler2.java
+++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceHandler2.java
@@ -172,7 +172,7 @@ public class TestLoadBalanceHandler2 {
     RegistryUtils.setServiceRegistry(serviceRegistry);
 
     when(serviceRegistry.getMicroserviceInstance()).thenReturn(myself);
-    when(serviceRegistry.getInstanceCacheManager()).thenReturn(instanceCacheManager);
+    mockUpInstanceCacheManager(instanceCacheManager);
     when(instanceCacheManager.getOrCreateVersionedCache("testApp", "testMicroserviceName", "0.0.0+"))
         .thenReturn(parent);
     when(transportManager.findTransport("rest")).thenReturn(transport);
@@ -299,7 +299,7 @@ public class TestLoadBalanceHandler2 {
     RegistryUtils.setServiceRegistry(serviceRegistry);
 
     when(serviceRegistry.getMicroserviceInstance()).thenReturn(myself);
-    when(serviceRegistry.getInstanceCacheManager()).thenReturn(instanceCacheManager);
+    mockUpInstanceCacheManager(instanceCacheManager);
     when(instanceCacheManager.getOrCreateVersionedCache("testApp", "testMicroserviceName", "0.0.0+"))
         .thenReturn(parent);
     when(transportManager.findTransport("rest")).thenReturn(transport);
@@ -410,7 +410,7 @@ public class TestLoadBalanceHandler2 {
     RegistryUtils.setServiceRegistry(serviceRegistry);
 
     when(serviceRegistry.getMicroserviceInstance()).thenReturn(myself);
-    when(serviceRegistry.getInstanceCacheManager()).thenReturn(instanceCacheManager);
+    mockUpInstanceCacheManager(instanceCacheManager);
     when(instanceCacheManager.getOrCreateVersionedCache("testApp", "testMicroserviceName", "0.0.0+"))
         .thenReturn(parent);
     when(transportManager.findTransport("rest")).thenReturn(transport);
@@ -537,7 +537,7 @@ public class TestLoadBalanceHandler2 {
     RegistryUtils.setServiceRegistry(serviceRegistry);
 
     when(serviceRegistry.getMicroserviceInstance()).thenReturn(myself);
-    when(serviceRegistry.getInstanceCacheManager()).thenReturn(instanceCacheManager);
+    mockUpInstanceCacheManager(instanceCacheManager);
     when(instanceCacheManager.getOrCreateVersionedCache("testApp", "testMicroserviceName", "0.0.0+"))
         .thenReturn(parent);
     when(transportManager.findTransport("rest")).thenReturn(transport);
@@ -681,7 +681,7 @@ public class TestLoadBalanceHandler2 {
     RegistryUtils.setServiceRegistry(serviceRegistry);
 
     when(serviceRegistry.getMicroserviceInstance()).thenReturn(myself);
-    when(serviceRegistry.getInstanceCacheManager()).thenReturn(instanceCacheManager);
+    mockUpInstanceCacheManager(instanceCacheManager);
     when(instanceCacheManager.getOrCreateVersionedCache("testApp", "testMicroserviceName", "0.0.0+"))
         .thenReturn(parent);
     when(transportManager.findTransport("rest")).thenReturn(transport);
@@ -800,7 +800,7 @@ public class TestLoadBalanceHandler2 {
     RegistryUtils.setServiceRegistry(serviceRegistry);
 
     when(serviceRegistry.getMicroserviceInstance()).thenReturn(myself);
-    when(serviceRegistry.getInstanceCacheManager()).thenReturn(instanceCacheManager);
+    mockUpInstanceCacheManager(instanceCacheManager);
     when(instanceCacheManager.getOrCreateVersionedCache("testApp", "testMicroserviceName", "0.0.0+"))
         .thenReturn(parent);
     when(transportManager.findTransport("rest")).thenReturn(transport);
@@ -983,4 +983,13 @@ public class TestLoadBalanceHandler2 {
   private void mockDelayMillis(long delay) {
     mockTimeMillis.value += delay;
   }
+
+  private void mockUpInstanceCacheManager(InstanceCacheManager instanceCacheManager) {
+    new MockUp<RegistryUtils>() {
+      @Mock
+      InstanceCacheManager getInstanceCacheManager() {
+        return instanceCacheManager;
+      }
+    };
+  }
 }
diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadbalanceHandler.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadbalanceHandler.java
index 6f3282e..94f484d 100644
--- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadbalanceHandler.java
+++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadbalanceHandler.java
@@ -35,6 +35,7 @@ import org.apache.servicecomb.core.transport.TransportManager;
 import org.apache.servicecomb.foundation.common.Holder;
 import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
 import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
+import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.ServiceRegistry;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
 import org.apache.servicecomb.serviceregistry.cache.CacheEndpoint;
@@ -99,7 +100,7 @@ public class TestLoadbalanceHandler {
   public static void classSetup() {
     scbEngine = new SCBBootstrap().useLocalRegistry().createSCBEngineForTest().run();
     serviceRegistry = scbEngine.getServiceRegistry();
-    instanceCacheManager = serviceRegistry.getInstanceCacheManager();
+    instanceCacheManager = RegistryUtils.getInstanceCacheManager();
     transportManager = scbEngine.getTransportManager();
   }
 
diff --git a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/ITUtils.java b/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/ITUtils.java
index 89efcca..f57e835 100644
--- a/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/ITUtils.java
+++ b/integration-tests/it-common/src/main/java/org/apache/servicecomb/it/ITUtils.java
@@ -77,7 +77,7 @@ public final class ITUtils {
 
     Map<String, MicroserviceInstance> instances;
     for (; ; ) {
-      MicroserviceVersionRule microserviceVersionRule = RegistryUtils.getServiceRegistry()
+      MicroserviceVersionRule microserviceVersionRule = RegistryUtils
           .getAppManager()
           .getOrCreateMicroserviceVersionRule(appId, microserviceName, strVersionRule);
       instances = microserviceVersionRule.getInstances();
@@ -92,7 +92,7 @@ public final class ITUtils {
           minInstanceCount,
           instances.size());
       // pull at once
-      RegistryUtils.getServiceRegistry().getAppManager().pullInstances();
+      RegistryUtils.getAppManager().pullInstances();
       forceWait(TimeUnit.SECONDS, 1);
     }
 
diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/MicroserviceDeploy.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/MicroserviceDeploy.java
index e24cfcb..4988caf 100644
--- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/MicroserviceDeploy.java
+++ b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/deploy/MicroserviceDeploy.java
@@ -55,7 +55,7 @@ public class MicroserviceDeploy extends NormalDeploy {
   }
 
   public void ensureReady() throws Throwable {
-    MicroserviceVersionRule microserviceVersionRule = RegistryUtils.getServiceRegistry().getAppManager()
+    MicroserviceVersionRule microserviceVersionRule = RegistryUtils.getAppManager()
         .getOrCreateMicroserviceVersionRule(microserviceDeployDefinition.getAppId(),
             microserviceDeployDefinition.getMicroserviceName(),
             microserviceDeployDefinition.getVersion());
diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/GateRestTemplate.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/GateRestTemplate.java
index 5fde52b..c9ea374 100644
--- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/GateRestTemplate.java
+++ b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/GateRestTemplate.java
@@ -70,7 +70,7 @@ public class GateRestTemplate extends RestTemplate {
   }
 
   private String getUrlPrefix(String gateName, String producerName, String schemaId) {
-    MicroserviceVersionRule microserviceVersionRule = RegistryUtils.getServiceRegistry().getAppManager()
+    MicroserviceVersionRule microserviceVersionRule = RegistryUtils.getAppManager()
         .getOrCreateMicroserviceVersionRule(RegistryUtils.getAppId(), gateName,
             DefinitionConst.VERSION_RULE_ALL);
     MicroserviceInstance microserviceInstance = microserviceVersionRule.getInstances().values().stream().findFirst()
diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBAsyncRestTemplate.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBAsyncRestTemplate.java
index 51aa2e5..21f55a8 100644
--- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBAsyncRestTemplate.java
+++ b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBAsyncRestTemplate.java
@@ -51,7 +51,7 @@ public class ITSCBAsyncRestTemplate extends CseAsyncRestTemplate {
     ensureProviderBasePath(producerName);
 
     urlPrefix = String.format("cse://%s%s", producerName, basePath);
-    instance = RegistryUtils.getServiceRegistry().getAppManager()
+    instance = RegistryUtils.getAppManager()
         .getOrCreateMicroserviceManager(RegistryUtils.getAppId())
         .getOrCreateMicroserviceVersions(producerName).getPulledInstances().get(0);
 
@@ -78,7 +78,7 @@ public class ITSCBAsyncRestTemplate extends CseAsyncRestTemplate {
 
   private void ensureProviderBasePath(String producerName) {
     MicroserviceManager microserviceManager =
-        RegistryUtils.getServiceRegistry().getAppManager().getOrCreateMicroserviceManager(RegistryUtils.getAppId());
+        RegistryUtils.getAppManager().getOrCreateMicroserviceManager(RegistryUtils.getAppId());
     MicroserviceVersions producerMicroserviceVersions =
         microserviceManager.getOrCreateMicroserviceVersions(producerName);
     Optional<MicroserviceVersion> latestMicroserviceVersion =
diff --git a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBRestTemplate.java b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBRestTemplate.java
index f83291b..f37d139 100644
--- a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBRestTemplate.java
+++ b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/extend/engine/ITSCBRestTemplate.java
@@ -48,7 +48,7 @@ public class ITSCBRestTemplate extends CseRestTemplate {
     SchemaMeta schemaMeta = microserviceMeta.ensureFindSchemaMeta(schemaId);
     basePath = schemaMeta.getSwagger().getBasePath();
     urlPrefix = String.format("cse://%s%s", producerName, basePath);
-    instance = RegistryUtils.getServiceRegistry().getAppManager()
+    instance = RegistryUtils.getAppManager()
         .getOrCreateMicroserviceManager(RegistryUtils.getAppId())
         .getOrCreateMicroserviceVersions(producerName).getPulledInstances().get(0);
 
diff --git a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/PreLoadBootListener.java b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/PreLoadBootListener.java
index e1e1343..b047ffa 100644
--- a/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/PreLoadBootListener.java
+++ b/integration-tests/it-edge/src/main/java/org/apache/servicecomb/it/edge/PreLoadBootListener.java
@@ -36,7 +36,7 @@ public class PreLoadBootListener implements BootListener {
   @Override
   public void onBootEvent(BootEvent bootEvent) {
     if (bootEvent.getEventType() == EventType.BEFORE_REGISTRY) {
-      MicroserviceVersionRule rule = RegistryUtils.getServiceRegistry().getAppManager()
+      MicroserviceVersionRule rule = RegistryUtils.getAppManager()
           .getOrCreateMicroserviceVersionRule(RegistryUtils.getAppId(), "it-producer", "0+");
       if (rule.getInstances().size() == 0) {
         LOGGER.warn("Prefetch not successful, maybe the provider not started.");
diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestTest.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestTest.java
index c80566f..ed6a0a4 100644
--- a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestTest.java
+++ b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestTest.java
@@ -25,6 +25,8 @@ import org.apache.servicecomb.core.SCBEngine;
 import org.apache.servicecomb.core.bootstrap.SCBBootstrap;
 import org.apache.servicecomb.foundation.common.Holder;
 import org.apache.servicecomb.provider.springmvc.reference.CseClientHttpResponse;
+import org.apache.servicecomb.serviceregistry.RegistryUtils;
+import org.apache.servicecomb.serviceregistry.consumer.AppManager;
 import org.apache.servicecomb.swagger.invocation.Response;
 import org.junit.AfterClass;
 import org.junit.Assert;
@@ -38,11 +40,14 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 
+import mockit.Deencapsulation;
+
 public class CseAsyncClientHttpRequestTest {
   static SCBEngine scbEngine;
 
   @BeforeClass
   public static void classSetup() {
+    Deencapsulation.setField(RegistryUtils.class, "appManager", new AppManager());
     scbEngine = new SCBBootstrap().useLocalRegistry().createSCBEngineForTest()
         .addProducerMeta("sid1", new CseAsyncClientHttpRequestTestSchema()).run();
   }
@@ -81,7 +86,7 @@ public class CseAsyncClientHttpRequestTest {
     byte[] body = "abc".getBytes();
     client.setRequestBody(body);
     client.executeAsync();
-    Assert.assertArrayEquals(body, ( byte[])holder.value.getInvocationArguments().get("input"));
+    Assert.assertArrayEquals(body, (byte[]) holder.value.getInvocationArguments().get("input"));
   }
 
   @Test
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
index cdfad6b..400adc5 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
@@ -32,11 +32,14 @@ import org.apache.servicecomb.foundation.common.net.NetUtils;
 import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
 import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager;
+import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManagerNew;
 import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient;
 import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances;
 import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
+import org.apache.servicecomb.serviceregistry.consumer.AppManager;
 import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition;
 import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryFactory;
+import org.apache.servicecomb.serviceregistry.swagger.SwaggerLoader;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -47,17 +50,23 @@ import com.netflix.config.DynamicPropertyFactory;
 public final class RegistryUtils {
   private static final Logger LOGGER = LoggerFactory.getLogger(RegistryUtils.class);
 
-  private static ServiceRegistry serviceRegistry;
+  private static volatile ServiceRegistry serviceRegistry;
 
   // value is ip or {interface name}
   public static final String PUBLISH_ADDRESS = "servicecomb.service.publishAddress";
 
   private static final String PUBLISH_PORT = "servicecomb.{transport_name}.publishPort";
 
+  private static SwaggerLoader swaggerLoader = new SwaggerLoader();
+
+  private static AppManager appManager = new AppManager();
+
+  private static InstanceCacheManager instanceCacheManager = new InstanceCacheManagerNew(appManager);
+
   private RegistryUtils() {
   }
 
-  public static void init() {
+  public static synchronized void init() {
     if (serviceRegistry != null) {
       return;
     }
@@ -66,7 +75,7 @@ public final class RegistryUtils {
     MicroserviceDefinition microserviceDefinition = new MicroserviceDefinition(loader.getConfigModels());
     serviceRegistry =
         ServiceRegistryFactory
-            .getOrCreate(EventManager.eventBus, ServiceRegistryConfig.INSTANCE, microserviceDefinition);
+            .create(EventManager.eventBus, ServiceRegistryConfig.INSTANCE, microserviceDefinition);
     serviceRegistry.init();
   }
 
@@ -99,7 +108,15 @@ public final class RegistryUtils {
   }
 
   public static InstanceCacheManager getInstanceCacheManager() {
-    return serviceRegistry.getInstanceCacheManager();
+    return instanceCacheManager;
+  }
+
+  public static SwaggerLoader getSwaggerLoader() {
+    return swaggerLoader;
+  }
+
+  public static AppManager getAppManager() {
+    return appManager;
   }
 
   public static String getAppId() {
@@ -234,4 +251,12 @@ public final class RegistryUtils {
   public static String calcSchemaSummary(String schemaContent) {
     return Hashing.sha256().newHasher().putString(schemaContent, Charsets.UTF_8).hash().toString();
   }
+
+  public static String getAggregatedSchema(String microserviceId, String schemaId) {
+    return serviceRegistry.getServiceRegistryClient().getAggregatedSchema(microserviceId, schemaId);
+  }
+
+  public static Microservice getAggregatedRemoteMicroservice(String microserviceId) {
+    return serviceRegistry.getAggregatedRemoteMicroservice(microserviceId);
+  }
 }
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/ServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/ServiceRegistry.java
index 9e1b144..d119cb8 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/ServiceRegistry.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/ServiceRegistry.java
@@ -22,11 +22,8 @@ import java.util.Set;
 
 import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
-import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager;
 import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient;
 import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances;
-import org.apache.servicecomb.serviceregistry.consumer.AppManager;
-import org.apache.servicecomb.serviceregistry.swagger.SwaggerLoader;
 
 import com.google.common.eventbus.EventBus;
 
@@ -39,22 +36,25 @@ public interface ServiceRegistry {
 
   EventBus getEventBus();
 
-  SwaggerLoader getSwaggerLoader();
-
   Set<String> getCombinedMicroserviceNames();
 
+  /**
+   * Get the AppId of this microservice instance itself.
+   */
   String getAppId();
 
+  /**
+   * Get the {@link Microservice} of this microservice instance itself.
+   */
   Microservice getMicroservice();
 
+  /**
+   * Get the {@link MicroserviceInstance} of this microservice instance itself.
+   */
   MicroserviceInstance getMicroserviceInstance();
 
   ServiceRegistryClient getServiceRegistryClient();
 
-  AppManager getAppManager();
-
-  InstanceCacheManager getInstanceCacheManager();
-
   List<MicroserviceInstance> findServiceInstance(String appId, String microserviceName,
       String microserviceVersionRule);
 
@@ -65,8 +65,6 @@ public interface ServiceRegistry {
 
   /**
    * full update, not increase update
-   * @param instanceProperties
-   * @return
    */
   boolean updateInstanceProperties(Map<String, String> instanceProperties);
 
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/AppManager.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/AppManager.java
index 24f4d6b..6cc2e50 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/AppManager.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/AppManager.java
@@ -20,30 +20,22 @@ package org.apache.servicecomb.serviceregistry.consumer;
 import java.util.Map;
 
 import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx;
-import org.apache.servicecomb.serviceregistry.ServiceRegistry;
+import org.apache.servicecomb.foundation.common.event.EventManager;
 import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent;
 import org.apache.servicecomb.serviceregistry.task.event.SafeModeChangeEvent;
 
 import com.google.common.eventbus.EventBus;
 
 public class AppManager {
-  private ServiceRegistry serviceRegistry;
-
   // key: appId
   private Map<String, MicroserviceManager> apps = new ConcurrentHashMapEx<>();
 
-  public AppManager(ServiceRegistry serviceRegistry) {
-    this.serviceRegistry = serviceRegistry;
-
+  public AppManager() {
     getEventBus().register(this);
   }
 
-  public ServiceRegistry getServiceRegistry() {
-    return serviceRegistry;
-  }
-
   public EventBus getEventBus() {
-    return serviceRegistry.getEventBus();
+    return EventManager.getEventBus();
   }
 
   public Map<String, MicroserviceManager> getApps() {
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersion.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersion.java
index d6953db..03ae5fe 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersion.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersion.java
@@ -21,6 +21,7 @@ import java.util.Collection;
 import java.util.List;
 
 import org.apache.servicecomb.foundation.common.VendorExtensions;
+import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
 import org.apache.servicecomb.serviceregistry.event.CreateMicroserviceVersionEvent;
@@ -47,10 +48,7 @@ public class MicroserviceVersion {
   public MicroserviceVersion(MicroserviceVersions microserviceVersions, String microserviceId,
       String microserviceName,
       Collection<MicroserviceInstance> instances) {
-    Microservice microservice = microserviceVersions
-        .getAppManager()
-        .getServiceRegistry()
-        .getAggregatedRemoteMicroservice(microserviceId);
+    Microservice microservice = RegistryUtils.getAggregatedRemoteMicroservice(microserviceId);
     if (microservice == null) {
       throw new IllegalStateException(
           String.format("failed to query by microserviceId '%s' from ServiceCenter.", microserviceId));
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java
index 66b81f6..8802a15 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/MicroserviceVersions.java
@@ -28,6 +28,7 @@ import java.util.Map.Entry;
 import org.apache.servicecomb.foundation.common.VendorExtensions;
 import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx;
 import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
+import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.api.Const;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
 import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent;
@@ -35,9 +36,9 @@ import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances;
 import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
 import org.apache.servicecomb.serviceregistry.definition.DefinitionConst;
 import org.apache.servicecomb.serviceregistry.definition.MicroserviceNameParser;
-import org.apache.servicecomb.serviceregistry.task.event.SafeModeChangeEvent;
 import org.apache.servicecomb.serviceregistry.event.CreateMicroserviceEvent;
 import org.apache.servicecomb.serviceregistry.event.DestroyMicroserviceEvent;
+import org.apache.servicecomb.serviceregistry.task.event.SafeModeChangeEvent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -177,7 +178,7 @@ public class MicroserviceVersions {
   }
 
   protected MicroserviceInstances findServiceInstances() {
-    return appManager.getServiceRegistry().findServiceInstances(appId,
+    return RegistryUtils.findServiceInstances(appId,
         microserviceName,
         DefinitionConst.VERSION_RULE_ALL,
         revision);
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersions.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersions.java
index 05e1323..ca34f1c 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersions.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/consumer/StaticMicroserviceVersions.java
@@ -20,6 +20,7 @@ package org.apache.servicecomb.serviceregistry.consumer;
 import java.util.List;
 import java.util.UUID;
 
+import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
 import org.apache.servicecomb.serviceregistry.api.response.FindInstancesResponse;
@@ -48,7 +49,7 @@ public class StaticMicroserviceVersions extends MicroserviceVersions {
   public StaticMicroserviceVersions init(Class<?> schemaIntfCls, String version,
       List<MicroserviceInstance> addedInstances) {
     this.schemaIntfCls = schemaIntfCls;
-    Swagger swagger = this.appManager.getServiceRegistry().getSwaggerLoader()
+    Swagger swagger = RegistryUtils.getSwaggerLoader()
         .registerSwagger(appId, shortName, shortName, schemaIntfCls);
     String swaggerContent = SwaggerUtils.swaggerToString(swagger);
     LOGGER.info("generate swagger for 3rd party service [{}]/[{}], swagger: {}",
@@ -88,7 +89,7 @@ public class StaticMicroserviceVersions extends MicroserviceVersions {
   }
 
   private void createMicroservice(String version) {
-    String environment = appManager.getServiceRegistry().getMicroservice().getEnvironment();
+    String environment = RegistryUtils.getMicroservice().getEnvironment();
 
     microservice.setAppId(this.getAppId());
     microservice.setServiceName(this.getShortName());
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/InstanceCacheCheckTask.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/InstanceCacheCheckTask.java
index b6dd615..21e0a90 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/InstanceCacheCheckTask.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/InstanceCacheCheckTask.java
@@ -20,6 +20,7 @@ import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.consumer.AppManager;
 import org.apache.servicecomb.serviceregistry.registry.RemoteServiceRegistry;
 import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryTaskInitializer;
@@ -86,7 +87,7 @@ public class InstanceCacheCheckTask implements ServiceRegistryTaskInitializer {
 
   @Override
   public void init(RemoteServiceRegistry remoteServiceRegistry) {
-    appManager = remoteServiceRegistry.getAppManager();
+    appManager = RegistryUtils.getAppManager();
     taskPool = remoteServiceRegistry.getTaskPool();
     eventBus = remoteServiceRegistry.getEventBus();
 
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/DiscoveryTree.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/DiscoveryTree.java
index 7158913..3180da7 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/DiscoveryTree.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/discovery/DiscoveryTree.java
@@ -116,7 +116,6 @@ public class DiscoveryTree {
   public DiscoveryTreeNode discovery(DiscoveryContext context, String appId, String microserviceName,
       String versionRule) {
     VersionedCache instanceVersionedCache = RegistryUtils
-        .getServiceRegistry()
         .getInstanceCacheManager()
         .getOrCreateVersionedCache(appId, microserviceName, versionRule);
 
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java
index 70cd5a0..a842db5 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java
@@ -28,6 +28,7 @@ import java.util.Set;
 import java.util.concurrent.ExecutorService;
 
 import org.apache.servicecomb.serviceregistry.Features;
+import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.ServiceRegistry;
 import org.apache.servicecomb.serviceregistry.api.Const;
 import org.apache.servicecomb.serviceregistry.api.registry.BasePath;
@@ -37,18 +38,14 @@ import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceFactory;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
 import org.apache.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent;
-import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager;
-import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManagerNew;
 import org.apache.servicecomb.serviceregistry.client.IpPortManager;
 import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient;
 import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances;
 import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
-import org.apache.servicecomb.serviceregistry.consumer.AppManager;
 import org.apache.servicecomb.serviceregistry.consumer.MicroserviceManager;
 import org.apache.servicecomb.serviceregistry.consumer.StaticMicroserviceVersions;
 import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition;
 import org.apache.servicecomb.serviceregistry.definition.MicroserviceNameParser;
-import org.apache.servicecomb.serviceregistry.swagger.SwaggerLoader;
 import org.apache.servicecomb.serviceregistry.task.MicroserviceServiceCenterTask;
 import org.apache.servicecomb.serviceregistry.task.ServiceCenterTask;
 import org.apache.servicecomb.serviceregistry.task.event.RecoveryEvent;
@@ -74,10 +71,6 @@ public abstract class AbstractServiceRegistry implements ServiceRegistry {
 
   protected Microservice microservice;
 
-  protected AppManager appManager;
-
-  protected InstanceCacheManager instanceCacheManager;
-
   protected IpPortManager ipPortManager;
 
   protected ServiceRegistryClient srClient;
@@ -86,8 +79,6 @@ public abstract class AbstractServiceRegistry implements ServiceRegistry {
 
   protected ServiceCenterTask serviceCenterTask;
 
-  protected SwaggerLoader swaggerLoader = new SwaggerLoader(this);
-
   protected ExecutorService executorService = MoreExecutors.newDirectExecutorService();
 
   public AbstractServiceRegistry(EventBus eventBus, ServiceRegistryConfig serviceRegistryConfig,
@@ -100,9 +91,7 @@ public abstract class AbstractServiceRegistry implements ServiceRegistry {
 
   @Override
   public void init() {
-    appManager = new AppManager(this);
-    instanceCacheManager = new InstanceCacheManagerNew(appManager);
-    ipPortManager = new IpPortManager(serviceRegistryConfig, instanceCacheManager);
+    ipPortManager = new IpPortManager(serviceRegistryConfig, RegistryUtils.getInstanceCacheManager());
     if (srClient == null) {
       srClient = createServiceRegistryClient();
     }
@@ -113,16 +102,6 @@ public abstract class AbstractServiceRegistry implements ServiceRegistry {
   }
 
   @Override
-  public SwaggerLoader getSwaggerLoader() {
-    return swaggerLoader;
-  }
-
-  @Override
-  public AppManager getAppManager() {
-    return appManager;
-  }
-
-  @Override
   public Features getFeatures() {
     return features;
   }
@@ -151,11 +130,6 @@ public abstract class AbstractServiceRegistry implements ServiceRegistry {
   }
 
   @Override
-  public InstanceCacheManager getInstanceCacheManager() {
-    return instanceCacheManager;
-  }
-
-  @Override
   public String getAppId() {
     return microservice.getAppId();
   }
@@ -315,10 +289,12 @@ public abstract class AbstractServiceRegistry implements ServiceRegistry {
   public void registerMicroserviceMapping(String microserviceName, String version,
       List<MicroserviceInstance> instances, Class<?> schemaIntfCls) {
     MicroserviceNameParser parser = new MicroserviceNameParser(microservice.getAppId(), microserviceName);
-    MicroserviceManager microserviceManager = appManager.getOrCreateMicroserviceManager(parser.getAppId());
+    MicroserviceManager microserviceManager = RegistryUtils.getAppManager()
+        .getOrCreateMicroserviceManager(parser.getAppId());
     microserviceManager.getVersionsByName()
         .computeIfAbsent(microserviceName,
-            svcName -> new StaticMicroserviceVersions(this.appManager, parser.getAppId(), microserviceName)
+            svcName -> new StaticMicroserviceVersions(RegistryUtils.getAppManager(), parser.getAppId(),
+                microserviceName)
                 .init(schemaIntfCls, version, instances)
         );
   }
@@ -345,17 +321,17 @@ public abstract class AbstractServiceRegistry implements ServiceRegistry {
   // post from watch eventloop, should refresh the exact microservice instances immediately
   @Subscribe
   public void onMicroserviceInstanceChanged(MicroserviceInstanceChangedEvent changedEvent) {
-    executorService.execute(() -> appManager.onMicroserviceInstanceChanged(changedEvent));
+    executorService.execute(() -> RegistryUtils.getAppManager().onMicroserviceInstanceChanged(changedEvent));
   }
 
   // post from watch eventloop, should refresh all instances immediately
   @Subscribe
   public void serviceRegistryRecovery(RecoveryEvent event) {
-    executorService.execute(appManager::pullInstances);
+    executorService.execute(RegistryUtils.getAppManager()::pullInstances);
   }
 
   @Subscribe
   public void onSafeModeChanged(SafeModeChangeEvent modeChangeEvent) {
-    executorService.execute(() -> appManager.onSafeModeChanged(modeChangeEvent));
+    executorService.execute(() -> RegistryUtils.getAppManager().onSafeModeChanged(modeChangeEvent));
   }
 }
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java
index 72bd255..123017c 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java
@@ -23,6 +23,7 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.servicecomb.foundation.common.concurrency.SuppressedRunnableWrapper;
 import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
+import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient;
 import org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl;
 import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
@@ -83,7 +84,7 @@ public class RemoteServiceRegistry extends AbstractServiceRegistry {
         TimeUnit.SECONDS);
 
     taskPool.scheduleAtFixedRate(
-        new SuppressedRunnableWrapper(appManager::pullInstances),
+        new SuppressedRunnableWrapper(RegistryUtils.getAppManager()::pullInstances),
         serviceRegistryConfig.getInstancePullInterval(),
         serviceRegistryConfig.getInstancePullInterval(),
         TimeUnit.SECONDS);
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryFactory.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryFactory.java
index ce44b79..0dab855 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryFactory.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/ServiceRegistryFactory.java
@@ -35,29 +35,9 @@ import com.google.common.eventbus.EventBus;
 public final class ServiceRegistryFactory {
   private static final Logger LOGGER = LoggerFactory.getLogger(ServiceRegistryFactory.class);
 
-  private static final Object LOCK = new Object();
-
-  private static volatile ServiceRegistry serviceRegistry;
-
   private ServiceRegistryFactory() {
   }
 
-  public static ServiceRegistry getServiceRegistry() {
-    return serviceRegistry;
-  }
-
-  public static ServiceRegistry getOrCreate(EventBus eventBus, ServiceRegistryConfig serviceRegistryConfig,
-      MicroserviceDefinition microserviceDefinition) {
-    if (serviceRegistry == null) {
-      synchronized (LOCK) {
-        if (serviceRegistry == null) {
-          serviceRegistry = create(eventBus, serviceRegistryConfig, microserviceDefinition);
-        }
-      }
-    }
-    return serviceRegistry;
-  }
-
   public static ServiceRegistry createLocal() {
     return createLocal(System.getProperty(LocalServiceRegistryClientImpl.LOCAL_REGISTRY_FILE_KEY));
   }
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/swagger/SwaggerLoader.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/swagger/SwaggerLoader.java
index d04c23d..fb07b7e 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/swagger/SwaggerLoader.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/swagger/SwaggerLoader.java
@@ -27,7 +27,7 @@ import org.apache.commons.io.FilenameUtils;
 import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx;
 import org.apache.servicecomb.foundation.common.utils.JvmUtils;
 import org.apache.servicecomb.foundation.common.utils.ResourceUtil;
-import org.apache.servicecomb.serviceregistry.ServiceRegistry;
+import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
 import org.apache.servicecomb.serviceregistry.definition.MicroserviceNameParser;
 import org.apache.servicecomb.swagger.SwaggerUtils;
@@ -40,15 +40,12 @@ import io.swagger.models.Swagger;
 public class SwaggerLoader {
   private static final Logger LOGGER = LoggerFactory.getLogger(SwaggerLoader.class);
 
-  private ServiceRegistry serviceRegistry;
-
   // first key : appId
   // second key: microservice short name
   // third key : schemaId
   private Map<String, Map<String, Map<String, Swagger>>> apps = new ConcurrentHashMapEx<>();
 
-  public SwaggerLoader(ServiceRegistry serviceRegistry) {
-    this.serviceRegistry = serviceRegistry;
+  public SwaggerLoader() {
   }
 
   /**
@@ -67,7 +64,7 @@ public class SwaggerLoader {
    * @param swaggersLocation eg. "test/schemas", will load all test/schemas/*.yaml
    */
   public void registerSwaggersInLocation(String swaggersLocation) {
-    String microserviceName = serviceRegistry.getMicroservice().getServiceName();
+    String microserviceName = RegistryUtils.getMicroservice().getServiceName();
     registerSwaggersInLocation(microserviceName, swaggersLocation);
   }
 
@@ -93,7 +90,7 @@ public class SwaggerLoader {
   }
 
   public void registerSwagger(String schemaId, Swagger swagger) {
-    registerSwagger(serviceRegistry.getMicroservice().getServiceName(), schemaId, swagger);
+    registerSwagger(RegistryUtils.getMicroservice().getServiceName(), schemaId, swagger);
   }
 
   public void registerSwagger(String microserviceName, String schemaId, String swaggerContent) {
@@ -108,7 +105,7 @@ public class SwaggerLoader {
   }
 
   public void registerSwagger(String microserviceName, String schemaId, Swagger swagger) {
-    MicroserviceNameParser parser = new MicroserviceNameParser(serviceRegistry.getAppId(), microserviceName);
+    MicroserviceNameParser parser = new MicroserviceNameParser(RegistryUtils.getAppId(), microserviceName);
     registerSwagger(parser.getAppId(), parser.getShortName(), schemaId, swagger);
   }
 
@@ -160,7 +157,7 @@ public class SwaggerLoader {
   }
 
   private Swagger loadFromResource(String appId, String shortName, String schemaId) {
-    if (appId.equals(serviceRegistry.getAppId())) {
+    if (appId.equals(RegistryUtils.getAppId())) {
       Swagger swagger = loadFromResource(String.format("microservices/%s/%s.yaml", shortName, schemaId));
       if (swagger != null) {
         return swagger;
@@ -181,7 +178,7 @@ public class SwaggerLoader {
   }
 
   private Swagger loadFromRemote(Microservice microservice, String schemaId) {
-    String schemaContent = serviceRegistry.getServiceRegistryClient()
+    String schemaContent = RegistryUtils
         .getAggregatedSchema(microservice.getServiceId(), schemaId);
     if (schemaContent != null) {
       LOGGER.info(
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/MockMicroserviceVersions.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/MockMicroserviceVersions.java
index 629628d..3d183b1 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/MockMicroserviceVersions.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/MockMicroserviceVersions.java
@@ -30,7 +30,6 @@ import org.apache.servicecomb.serviceregistry.consumer.AppManager;
 import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersion;
 import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionRule;
 import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersions;
-import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryFactory;
 import org.apache.servicecomb.serviceregistry.version.Version;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
@@ -45,14 +44,16 @@ public class MockMicroserviceVersions extends MicroserviceVersions {
   private List<MicroserviceInstance> mockedInstances = new ArrayList<>();
 
   public MockMicroserviceVersions() {
-    super(new AppManager(ServiceRegistryFactory.createLocal()), "appId", "msName");
+    super(new AppManager(), "appId", "msName");
 
-    new MockUp<ServiceRegistry>(appManager.getServiceRegistry()) {
+    ServiceRegistry serviceRegistry = new MockUp<ServiceRegistry>() {
       @Mock
       Microservice getAggregatedRemoteMicroservice(String microserviceId) {
         return mockedMicroservices.get(microserviceId);
       }
-    };
+    }.getMockInstance();
+
+    RegistryUtils.setServiceRegistry(serviceRegistry);
 
     addMock("1.0.0", 2);
     addMock("2.0.0", 2);
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestConsumers.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestConsumers.java
index 737e47d..b5c009c 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestConsumers.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestConsumers.java
@@ -109,9 +109,9 @@ public class TestConsumers extends TestRegistryBase {
 
   @Test
   public void deleteWhenCreateMicroserviceVersion() {
-    new Expectations(appManager.getServiceRegistry()) {
+    new Expectations(RegistryUtils.getServiceRegistry()) {
       {
-        appManager.getServiceRegistry().getAggregatedRemoteMicroservice(serviceId);
+        RegistryUtils.getServiceRegistry().getAggregatedRemoteMicroservice(serviceId);
         result = null;
       }
     };
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistry.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistry.java
index cd6ad04..63d1d8b 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistry.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistry.java
@@ -89,7 +89,6 @@ public class TestRegistry {
     Assert.assertEquals(serviceRegistry, RegistryUtils.getServiceRegistry());
 
     Assert.assertEquals(serviceRegistry.getServiceRegistryClient(), RegistryUtils.getServiceRegistryClient());
-    Assert.assertEquals(serviceRegistry.getInstanceCacheManager(), RegistryUtils.getInstanceCacheManager());
 
     Microservice microservice = RegistryUtils.getMicroservice();
     Assert.assertEquals(serviceRegistry.getMicroservice(), microservice);
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistryBase.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistryBase.java
index 3a6ac2f..267af9c 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistryBase.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistryBase.java
@@ -29,6 +29,7 @@ import org.junit.Before;
 
 import com.google.common.eventbus.EventBus;
 
+import mockit.Deencapsulation;
 import mockit.Expectations;
 
 public class TestRegistryBase {
@@ -66,11 +67,12 @@ public class TestRegistryBase {
     serviceRegistry = ServiceRegistryFactory.createLocal("registry.yaml");
     serviceRegistry.init();
 
-    appManager = serviceRegistry.getAppManager();
+    Deencapsulation.setField(RegistryUtils.class, "appManager", new AppManager());
+    appManager = RegistryUtils.getAppManager();
     microserviceManager = appManager.getOrCreateMicroserviceManager(appId);
     eventBus = serviceRegistry.getEventBus();
 
-    serviceRegistry.getSwaggerLoader().registerSwagger(appId, serviceName, schemaId, Hello.class);
+    RegistryUtils.getSwaggerLoader().registerSwagger(appId, serviceName, schemaId, Hello.class);
 
     RegistryUtils.setServiceRegistry(serviceRegistry);
 
@@ -86,9 +88,9 @@ public class TestRegistryBase {
   protected void mockNotExist() {
     MicroserviceInstances microserviceInstances = new MicroserviceInstances();
     microserviceInstances.setMicroserviceNotExist(true);
-    new Expectations(appManager.getServiceRegistry()) {
+    new Expectations(RegistryUtils.getServiceRegistry()) {
       {
-        appManager.getServiceRegistry()
+        RegistryUtils.getServiceRegistry()
             .findServiceInstances(anyString, anyString, DefinitionConst.VERSION_RULE_ALL, anyString);
         result = microserviceInstances;
       }
@@ -96,9 +98,9 @@ public class TestRegistryBase {
   }
 
   protected void mockDisconnect() {
-    new Expectations(appManager.getServiceRegistry()) {
+    new Expectations(RegistryUtils.getServiceRegistry()) {
       {
-        appManager.getServiceRegistry()
+        RegistryUtils.getServiceRegistry()
             .findServiceInstances(anyString, anyString, DefinitionConst.VERSION_RULE_ALL, anyString);
         result = null;
       }
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheChecker.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheChecker.java
index 66bb06a..133535c 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheChecker.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheChecker.java
@@ -27,6 +27,7 @@ import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
 import org.apache.servicecomb.serviceregistry.api.response.FindInstancesResponse;
 import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances;
+import org.apache.servicecomb.serviceregistry.consumer.AppManager;
 import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersionRule;
 import org.apache.servicecomb.serviceregistry.consumer.MicroserviceVersions;
 import org.apache.servicecomb.serviceregistry.definition.DefinitionConst;
@@ -38,6 +39,7 @@ import org.junit.Before;
 import org.junit.Test;
 
 import io.vertx.core.json.Json;
+import mockit.Deencapsulation;
 import mockit.Mock;
 import mockit.MockUp;
 
@@ -54,10 +56,12 @@ public class TestInstanceCacheChecker {
 
   @Before
   public void setUp() throws Exception {
+    Deencapsulation.setField(RegistryUtils.class, "appManager", new AppManager());
+
     serviceRegistry.init();
     RegistryUtils.setServiceRegistry(serviceRegistry);
 
-    checker = new InstanceCacheChecker(serviceRegistry.getAppManager());
+    checker = new InstanceCacheChecker(RegistryUtils.getAppManager());
     checker.clock = new MockClock(new Holder<>(1L));
     expectedSummary.setStatus(Status.NORMAL);
     expectedSummary.setTimestamp(1);
@@ -78,7 +82,7 @@ public class TestInstanceCacheChecker {
   @Test
   public void check_microserviceManager_empty() {
     appId = "notExist";
-    serviceRegistry.getAppManager().getOrCreateMicroserviceVersions(appId, microserviceName);
+    RegistryUtils.getAppManager().getOrCreateMicroserviceVersions(appId, microserviceName);
     InstanceCacheSummary instanceCacheSummary = checker.check();
     Assert.assertEquals(Json.encode(expectedSummary), Json.encode(instanceCacheSummary));
   }
@@ -119,7 +123,7 @@ public class TestInstanceCacheChecker {
 
     registerMicroservice(appId, microserviceName);
 
-    serviceRegistry.getAppManager()
+    RegistryUtils.getAppManager()
         .getOrCreateMicroserviceVersionRule(appId, microserviceName, DefinitionConst.VERSION_RULE_ALL);
 
     findHolder.value = null;
@@ -151,7 +155,7 @@ public class TestInstanceCacheChecker {
 
     registerMicroservice(appId, microserviceName);
 
-    serviceRegistry.getAppManager()
+    RegistryUtils.getAppManager()
         .getOrCreateMicroserviceVersionRule(appId, microserviceName, DefinitionConst.VERSION_RULE_ALL);
 
     findHolder.value.setMicroserviceNotExist(true);
@@ -183,7 +187,7 @@ public class TestInstanceCacheChecker {
 
     registerMicroservice(appId, microserviceName);
 
-    serviceRegistry.getAppManager()
+    RegistryUtils.getAppManager()
         .getOrCreateMicroserviceVersionRule(appId, microserviceName, DefinitionConst.VERSION_RULE_ALL);
 
     findHolder.value.setRevision("second");
@@ -216,7 +220,7 @@ public class TestInstanceCacheChecker {
 
     registerMicroservice(appId, microserviceName);
 
-    MicroserviceVersions microserviceVersions = serviceRegistry.getAppManager()
+    MicroserviceVersions microserviceVersions = RegistryUtils.getAppManager()
         .getOrCreateMicroserviceVersions(appId, microserviceName);
     microserviceVersions.setRevision("first");
     microserviceVersions.getOrCreateMicroserviceVersionRule(DefinitionConst.VERSION_RULE_ALL);
@@ -248,7 +252,7 @@ public class TestInstanceCacheChecker {
         Arrays.asList("rest://localhost:8080"),
         ThirdPartyServiceForUT.class);
 
-    MicroserviceVersionRule microserviceVersionRule = serviceRegistry.getAppManager()
+    MicroserviceVersionRule microserviceVersionRule = RegistryUtils.getAppManager()
         .getOrCreateMicroserviceVersionRule(appId, microserviceName, DefinitionConst.VERSION_RULE_ALL);
     Assert.assertEquals(microserviceName, microserviceVersionRule.getLatestMicroserviceVersion().getMicroserviceName());
 
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestDiscoveryTree.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestDiscoveryTree.java
index 6402858..0940270 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestDiscoveryTree.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/discovery/TestDiscoveryTree.java
@@ -24,7 +24,6 @@ import org.apache.servicecomb.foundation.common.cache.VersionedCache;
 import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException;
 import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
 import org.apache.servicecomb.serviceregistry.RegistryUtils;
-import org.apache.servicecomb.serviceregistry.ServiceRegistry;
 import org.apache.servicecomb.serviceregistry.cache.InstanceCacheManager;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
@@ -125,7 +124,7 @@ public class TestDiscoveryTree {
     Assert.assertFalse(discoveryTree.isExpired(new DiscoveryTreeNode().cacheVersion(0), parent));
   }
 
-  class DiscoveryFilterForTest implements DiscoveryFilter {
+  static class DiscoveryFilterForTest implements DiscoveryFilter {
     protected String groupName;
 
     public DiscoveryFilterForTest(String groupName) {
@@ -167,13 +166,10 @@ public class TestDiscoveryTree {
   }
 
   @Test
-  public void easyDiscovery(@Mocked ServiceRegistry serviceRegistry,
-      @Mocked InstanceCacheManager instanceCacheManager) {
+  public void easyDiscovery(@Mocked InstanceCacheManager instanceCacheManager) {
     new Expectations(RegistryUtils.class) {
       {
-        RegistryUtils.getServiceRegistry();
-        result = serviceRegistry;
-        serviceRegistry.getInstanceCacheManager();
+        RegistryUtils.getInstanceCacheManager();
         result = instanceCacheManager;
         instanceCacheManager.getOrCreateVersionedCache(anyString, anyString, anyString);
         result = parent;
@@ -186,13 +182,10 @@ public class TestDiscoveryTree {
   }
 
   @Test
-  public void discovery_filterReturnNull(@Mocked ServiceRegistry serviceRegistry,
-      @Mocked InstanceCacheManager instanceCacheManager) {
+  public void discovery_filterReturnNull(@Mocked InstanceCacheManager instanceCacheManager) {
     new Expectations(RegistryUtils.class) {
       {
-        RegistryUtils.getServiceRegistry();
-        result = serviceRegistry;
-        serviceRegistry.getInstanceCacheManager();
+        RegistryUtils.getInstanceCacheManager();
         result = instanceCacheManager;
         instanceCacheManager.getOrCreateVersionedCache(anyString, anyString, anyString);
         result = parent;
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestServiceRegistryFactory.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestServiceRegistryFactory.java
index 07f7e08..77e8aa4 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestServiceRegistryFactory.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestServiceRegistryFactory.java
@@ -30,7 +30,6 @@ import org.junit.Test;
 
 import com.google.common.eventbus.EventBus;
 
-import mockit.Deencapsulation;
 import mockit.Mocked;
 
 /**
@@ -52,20 +51,17 @@ public class TestServiceRegistryFactory {
     ServiceRegistryClient client = serviceRegistry.getServiceRegistryClient();
     Assert.assertTrue(client instanceof ServiceRegistryClientImpl);
 
-    serviceRegistry = ServiceRegistryFactory.getOrCreate(eventBus,
+    serviceRegistry = ServiceRegistryFactory.create(eventBus,
         serviceRegistryConfig,
         microserviceDefinition);
     Assert.assertTrue(serviceRegistry instanceof RemoteServiceRegistry);
-    Assert.assertEquals(serviceRegistry, ServiceRegistryFactory.getServiceRegistry());
-
-    Deencapsulation.setField(ServiceRegistryFactory.class, "serviceRegistry", null);
 
     System.setProperty("local.registry.file", "/tmp/test.yaml");
     serviceRegistry = ServiceRegistryFactory.create(eventBus, serviceRegistryConfig, microserviceDefinition);
     serviceRegistry.init();
     client = serviceRegistry.getServiceRegistryClient();
     Assert.assertTrue(client instanceof LocalServiceRegistryClientImpl);
-    Assert.assertTrue(ServiceRegistryFactory.getOrCreate(eventBus,
+    Assert.assertTrue(ServiceRegistryFactory.create(eventBus,
         serviceRegistryConfig,
         microserviceDefinition) instanceof LocalServiceRegistry);
     System.clearProperty("local.registry.file");
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/swagger/TestSwaggerLoader.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/swagger/TestSwaggerLoader.java
index e4b8752..48623f0 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/swagger/TestSwaggerLoader.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/swagger/TestSwaggerLoader.java
@@ -40,6 +40,7 @@ import org.apache.servicecomb.foundation.common.Holder;
 import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException;
 import org.apache.servicecomb.foundation.common.utils.JvmUtils;
 import org.apache.servicecomb.foundation.common.utils.ResourceUtil;
+import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.TestRegistryBase;
 import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
 import org.apache.servicecomb.swagger.SwaggerUtils;
@@ -62,11 +63,11 @@ public class TestSwaggerLoader extends TestRegistryBase {
   @Test
   public void registerSwagger() {
     Swagger swagger = SwaggerGenerator.generate(Hello.class);
-    serviceRegistry.getSwaggerLoader().registerSwagger("default:ms2", schemaId, swagger);
+    RegistryUtils.getSwaggerLoader().registerSwagger("default:ms2", schemaId, swagger);
 
     Microservice microservice = appManager.getOrCreateMicroserviceVersions(appId, serviceName)
         .getVersions().values().iterator().next().getMicroservice();
-    Assert.assertSame(swagger, serviceRegistry.getSwaggerLoader().loadSwagger(microservice, schemaId));
+    Assert.assertSame(swagger, RegistryUtils.getSwaggerLoader().loadSwagger(microservice, schemaId));
   }
 
   @Test
@@ -79,11 +80,11 @@ public class TestSwaggerLoader extends TestRegistryBase {
       }
     };
 
-    serviceRegistry.getSwaggerLoader().unregisterSwagger(appId, serviceName, schemaId);
+    RegistryUtils.getSwaggerLoader().unregisterSwagger(appId, serviceName, schemaId);
 
     Microservice microservice = appManager.getOrCreateMicroserviceVersions(appId, serviceName)
         .getVersions().values().iterator().next().getMicroservice();
-    Swagger loadedSwagger = serviceRegistry.getSwaggerLoader().loadSwagger(microservice, schemaId);
+    Swagger loadedSwagger = RegistryUtils.getSwaggerLoader().loadSwagger(microservice, schemaId);
     Assert.assertNotSame(swagger, loadedSwagger);
     Assert.assertEquals(swagger, loadedSwagger);
   }
@@ -93,11 +94,11 @@ public class TestSwaggerLoader extends TestRegistryBase {
     Swagger swagger = SwaggerGenerator.generate(Hello.class);
     mockLocalResource(swagger, String.format("microservices/%s/%s.yaml", serviceName, schemaId));
 
-    serviceRegistry.getSwaggerLoader().unregisterSwagger(appId, serviceName, schemaId);
+    RegistryUtils.getSwaggerLoader().unregisterSwagger(appId, serviceName, schemaId);
 
     Microservice microservice = appManager.getOrCreateMicroserviceVersions(appId, serviceName)
         .getVersions().values().iterator().next().getMicroservice();
-    Swagger loadedSwagger = serviceRegistry.getSwaggerLoader().loadSwagger(microservice, schemaId);
+    Swagger loadedSwagger = RegistryUtils.getSwaggerLoader().loadSwagger(microservice, schemaId);
     Assert.assertNotSame(swagger, loadedSwagger);
     Assert.assertEquals(swagger, loadedSwagger);
   }
@@ -107,11 +108,11 @@ public class TestSwaggerLoader extends TestRegistryBase {
     Swagger swagger = SwaggerGenerator.generate(Hello.class);
     mockLocalResource(swagger, String.format("applications/%s/%s/%s.yaml", appId, serviceName, schemaId));
 
-    serviceRegistry.getSwaggerLoader().unregisterSwagger(appId, serviceName, schemaId);
+    RegistryUtils.getSwaggerLoader().unregisterSwagger(appId, serviceName, schemaId);
 
     Microservice microservice = appManager.getOrCreateMicroserviceVersions(appId, serviceName)
         .getVersions().values().iterator().next().getMicroservice();
-    Swagger loadedSwagger = serviceRegistry.getSwaggerLoader().loadSwagger(microservice, schemaId);
+    Swagger loadedSwagger = RegistryUtils.getSwaggerLoader().loadSwagger(microservice, schemaId);
     Assert.assertNotSame(swagger, loadedSwagger);
     Assert.assertEquals(swagger, loadedSwagger);
   }
@@ -127,7 +128,7 @@ public class TestSwaggerLoader extends TestRegistryBase {
     expectedException.expect(IllegalStateException.class);
     expectedException.expectMessage(
         "no schema in local, and can not get schema from service center, appId=other, microserviceName=ms3, version=1.0, serviceId=003, schemaId=hello.");
-    serviceRegistry.getSwaggerLoader().loadSwagger(microservice, schemaId);
+    RegistryUtils.getSwaggerLoader().loadSwagger(microservice, schemaId);
   }
 
   @Test
@@ -137,7 +138,7 @@ public class TestSwaggerLoader extends TestRegistryBase {
 
     Microservice microservice = appManager.getOrCreateMicroserviceVersions("other", "ms3")
         .getVersions().values().iterator().next().getMicroservice();
-    Swagger loadedSwagger = serviceRegistry.getSwaggerLoader().loadSwagger(microservice, schemaId);
+    Swagger loadedSwagger = RegistryUtils.getSwaggerLoader().loadSwagger(microservice, schemaId);
     Assert.assertNotSame(swagger, loadedSwagger);
     Assert.assertEquals(swagger, loadedSwagger);
   }
@@ -195,16 +196,16 @@ public class TestSwaggerLoader extends TestRegistryBase {
 
   @Test
   public void should_ignore_not_exist_location_when_register_swagger_in_location() {
-    Map<String, Object> apps = Deencapsulation.getField(serviceRegistry.getSwaggerLoader(), "apps");
+    Map<String, Object> apps = Deencapsulation.getField(RegistryUtils.getSwaggerLoader(), "apps");
     apps.clear();
-    serviceRegistry.getSwaggerLoader().registerSwaggersInLocation("notExistPath");
+    RegistryUtils.getSwaggerLoader().registerSwaggersInLocation("notExistPath");
     assertThat(apps).isEmpty();
   }
 
   @Test
   public void should_ignore_non_yaml_file_when_register_swagger_in_location() {
-    serviceRegistry.getSwaggerLoader().registerSwaggersInLocation("swagger-del");
-    assertThat(serviceRegistry.getSwaggerLoader().loadFromMemory(appId, serviceName, "other")).isNull();
+    RegistryUtils.getSwaggerLoader().registerSwaggersInLocation("swagger-del");
+    assertThat(RegistryUtils.getSwaggerLoader().loadFromMemory(appId, serviceName, "other")).isNull();
   }
 
   @Test
@@ -248,12 +249,12 @@ public class TestSwaggerLoader extends TestRegistryBase {
       }
     };
 
-    serviceRegistry.getSwaggerLoader().registerSwaggersInLocation("location");
+    RegistryUtils.getSwaggerLoader().registerSwaggersInLocation("location");
   }
 
   @Test
   public void should_correct_register_swagger_in_location() {
-    serviceRegistry.getSwaggerLoader().registerSwaggersInLocation("swagger-del");
-    assertThat(serviceRegistry.getSwaggerLoader().loadFromMemory(appId, serviceName, "hello")).isNotNull();
+    RegistryUtils.getSwaggerLoader().registerSwaggersInLocation("swagger-del");
+    assertThat(RegistryUtils.getSwaggerLoader().loadFromMemory(appId, serviceName, "hello")).isNotNull();
   }
 }


[servicecomb-java-chassis] 03/19: [SCB-1691] add name for ServiceRegistry

Posted by ya...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

yaohaishi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit bf3292b0c8e36c5cf698ba9328e149dab49d1c2c
Author: yhs0092 <yh...@163.com>
AuthorDate: Sat Jan 4 15:46:37 2020 +0800

    [SCB-1691] add name for ServiceRegistry
---
 .../servicecomb/serviceregistry/RegistryUtils.java | 17 ++++++
 .../serviceregistry/ServiceRegistry.java           | 11 ++++
 .../config/ServiceRegistryConfig.java              | 13 ++++-
 .../registry/AbstractServiceRegistry.java          | 13 +++++
 .../registry/RemoteServiceRegistry.java            |  3 +-
 .../serviceregistry/ServiceRegistryTest.java       | 68 ++++++++++++++++++++++
 .../registry/TestRemoteServiceRegistry.java        |  2 +
 7 files changed, 125 insertions(+), 2 deletions(-)

diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
index 400adc5..46de489 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
@@ -22,6 +22,8 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.regex.Matcher;
 
 import org.apache.http.client.utils.URIBuilder;
 import org.apache.servicecomb.config.ConfigUtil;
@@ -259,4 +261,19 @@ public final class RegistryUtils {
   public static Microservice getAggregatedRemoteMicroservice(String microserviceId) {
     return serviceRegistry.getAggregatedRemoteMicroservice(microserviceId);
   }
+
+  /**
+   * To validate whether the name is legal value.
+   * @param name name of the {@link ServiceRegistry}
+   * @throws IllegalArgumentException the input value is illegal
+   */
+  public static void validateRegistryName(String name) {
+    Objects.requireNonNull(name, "null value is not allowed for the name of ServiceRegistry");
+    Matcher checkMatcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher(name);
+    boolean isNameValid = checkMatcher.matches();
+    if (!isNameValid) {
+      throw new IllegalArgumentException(
+          "Illegal registry name, the format should be " + ServiceRegistry.REGISTRY_NAME_FORMAT);
+    }
+  }
 }
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/ServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/ServiceRegistry.java
index d119cb8..0e6e1a2 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/ServiceRegistry.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/ServiceRegistry.java
@@ -19,6 +19,7 @@ package org.apache.servicecomb.serviceregistry;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.regex.Pattern;
 
 import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
@@ -28,6 +29,16 @@ import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances;
 import com.google.common.eventbus.EventBus;
 
 public interface ServiceRegistry {
+  String DEFAULT_REGISTRY_NAME = "Default";
+  String REGISTRY_NAME_FORMAT = "[a-zA-Z]([-_]?[a-zA-Z0-9])+";
+  Pattern REGISTRY_NAME_PATTERN = Pattern.compile(REGISTRY_NAME_FORMAT);
+
+  /**
+   * Get a name representing this ServiceRegistry instance.
+   * The name should be unique.
+   */
+  String getName();
+
   void init();
 
   void run();
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
index 2badf45..9d5e440 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/config/ServiceRegistryConfig.java
@@ -26,6 +26,7 @@ import org.apache.servicecomb.deployment.Deployment;
 import org.apache.servicecomb.deployment.DeploymentProvider;
 import org.apache.servicecomb.foundation.common.net.IpPort;
 import org.apache.servicecomb.foundation.common.net.NetUtils;
+import org.apache.servicecomb.serviceregistry.ServiceRegistry;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -98,6 +99,8 @@ public final class ServiceRegistryConfig {
 
   public static final String WORKER_POOL_NAME = "registry-vert.x-worker-thread";
 
+  private String registryName = ServiceRegistry.DEFAULT_REGISTRY_NAME;
+
   private ServiceRegistryConfig() {
 
   }
@@ -124,7 +127,6 @@ public final class ServiceRegistryConfig {
     return deployInstances;
   }
 
-
   public boolean isSsl() {
     getIpPort();
     return this.ssl;
@@ -317,6 +319,15 @@ public final class ServiceRegistryConfig {
     return passwd;
   }
 
+  public String getRegistryName() {
+    return registryName;
+  }
+
+  public ServiceRegistryConfig setRegistryName(String registryName) {
+    this.registryName = registryName;
+    return this;
+  }
+
   private String getProperty(String defaultValue, String... keys) {
     String property = null;
     for (String key : keys) {
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java
index a842db5..baf25dc 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/AbstractServiceRegistry.java
@@ -81,8 +81,11 @@ public abstract class AbstractServiceRegistry implements ServiceRegistry {
 
   protected ExecutorService executorService = MoreExecutors.newDirectExecutorService();
 
+  private String name;
+
   public AbstractServiceRegistry(EventBus eventBus, ServiceRegistryConfig serviceRegistryConfig,
       MicroserviceDefinition microserviceDefinition) {
+    setName(serviceRegistryConfig.getRegistryName());
     this.eventBus = eventBus;
     this.serviceRegistryConfig = serviceRegistryConfig;
     this.microserviceDefinition = microserviceDefinition;
@@ -312,6 +315,16 @@ public abstract class AbstractServiceRegistry implements ServiceRegistry {
     registerMicroserviceMapping(microserviceName, version, microserviceInstances, schemaIntfCls);
   }
 
+  @Override
+  public String getName() {
+    return name;
+  }
+
+  void setName(String name) {
+    RegistryUtils.validateRegistryName(name);
+    this.name = name;
+  }
+
   @Subscribe
   public void onShutdown(ShutdownEvent event) {
     LOGGER.info("service center task is shutdown.");
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java
index 123017c..dfeee99 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/registry/RemoteServiceRegistry.java
@@ -58,7 +58,8 @@ public class RemoteServiceRegistry extends AbstractServiceRegistry {
 
           @Override
           public Thread newThread(Runnable r) {
-            Thread thread = new Thread(r, "Service Center Task [" + (taskId++) + "]");
+            Thread thread = new Thread(r,
+                RemoteServiceRegistry.super.getName() + " Service Center Task [" + (taskId++) + "]");
             thread.setUncaughtExceptionHandler(
                 (t, e) -> LOGGER.error("Service Center Task Thread is terminated! thread: [{}]", t, e));
             return thread;
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/ServiceRegistryTest.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/ServiceRegistryTest.java
new file mode 100644
index 0000000..3477fb6
--- /dev/null
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/ServiceRegistryTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.serviceregistry;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.regex.Matcher;
+
+import org.junit.Test;
+
+public class ServiceRegistryTest {
+  @Test
+  public void testNameFormat() {
+    Matcher matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("abc");
+    assertTrue(matcher.matches());
+    matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("abc00");
+    assertTrue(matcher.matches());
+    matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("ABC");
+    assertTrue(matcher.matches());
+    matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("A2BC");
+    assertTrue(matcher.matches());
+    matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("abc-ABC");
+    assertTrue(matcher.matches());
+    matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("abc_ABC");
+    assertTrue(matcher.matches());
+
+    matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("");
+    assertFalse(matcher.matches());
+    matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("-abc");
+    assertFalse(matcher.matches());
+    matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("abc-");
+    assertFalse(matcher.matches());
+    matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("_abc");
+    assertFalse(matcher.matches());
+    matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("abc_");
+    assertFalse(matcher.matches());
+    matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("0abc");
+    assertFalse(matcher.matches());
+    matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("ab.c");
+    assertFalse(matcher.matches());
+    matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("ab?c");
+    assertFalse(matcher.matches());
+    matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("ab#c");
+    assertFalse(matcher.matches());
+    matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("ab&c");
+    assertFalse(matcher.matches());
+    matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("ab*c");
+    assertFalse(matcher.matches());
+    matcher = ServiceRegistry.REGISTRY_NAME_PATTERN.matcher("ab@c");
+    assertFalse(matcher.matches());
+  }
+}
\ No newline at end of file
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestRemoteServiceRegistry.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestRemoteServiceRegistry.java
index d82fc75..c035aae 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestRemoteServiceRegistry.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/registry/TestRemoteServiceRegistry.java
@@ -90,6 +90,8 @@ public class TestRemoteServiceRegistry {
         result = 30;
         config.isWatch();
         result = false;
+        config.getRegistryName();
+        result = "TestRegistry";
         SPIServiceUtils.getOrLoadSortedService(ServiceRegistryTaskInitializer.class);
         result = Arrays.asList(initializer);
       }


[servicecomb-java-chassis] 05/19: [SCB-1691] ClientPool can be instantiated

Posted by ya...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

yaohaishi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit a407a983435b4747fc5df8862c1adf1fe6592fa0
Author: yhs0092 <yh...@163.com>
AuthorDate: Tue Jan 14 16:27:11 2020 +0800

    [SCB-1691] ClientPool can be instantiated
---
 .../client/http/AbstractClientPool.java            | 34 ++++++++++++----------
 .../serviceregistry/client/http/ClientPool.java    |  6 +---
 .../client/http/HttpClientPool.java                | 32 ++++++++++++--------
 .../client/http/WebsocketClientPool.java           | 16 ++++++----
 .../client/http/TestHttpClientPool.java            | 12 +++++---
 .../client/http/TestWebsocketClientPool.java       |  7 +++--
 6 files changed, 63 insertions(+), 44 deletions(-)

diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/AbstractClientPool.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/AbstractClientPool.java
index 5992c05..968d858 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/AbstractClientPool.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/AbstractClientPool.java
@@ -17,9 +17,6 @@
 
 package org.apache.servicecomb.serviceregistry.client.http;
 
-import com.netflix.config.DynamicIntProperty;
-import com.netflix.config.DynamicPropertyFactory;
-
 import org.apache.servicecomb.foundation.vertx.AddressResolverConfig;
 import org.apache.servicecomb.foundation.vertx.VertxUtils;
 import org.apache.servicecomb.foundation.vertx.client.ClientPoolManager;
@@ -30,6 +27,9 @@ import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.netflix.config.DynamicIntProperty;
+import com.netflix.config.DynamicPropertyFactory;
+
 import io.vertx.core.DeploymentOptions;
 import io.vertx.core.Vertx;
 import io.vertx.core.VertxOptions;
@@ -38,12 +38,15 @@ import io.vertx.core.http.HttpClientOptions;
 /**
  * Created by  on 2017/4/28.
  */
-public abstract class AbstractClientPool implements ClientPool {
+abstract class AbstractClientPool implements ClientPool {
   private static final Logger LOGGER = LoggerFactory.getLogger(AbstractClientPool.class);
 
-    private ClientPoolManager<HttpClientWithContext> clientMgr;
+  private HttpClientOptions httpClientOptions;
+
+  private ClientPoolManager<HttpClientWithContext> clientMgr;
 
-  public AbstractClientPool() {
+  AbstractClientPool(HttpClientOptions httpClientOptions) {
+    this.httpClientOptions = httpClientOptions;
     create();
   }
 
@@ -54,22 +57,23 @@ public abstract class AbstractClientPool implements ClientPool {
   }
 
   public void create() {
-    DynamicIntProperty property = DynamicPropertyFactory.getInstance().getIntProperty(ServiceRegistryConfig.EVENT_LOOP_POOL_SIZE, 4);
-    DynamicIntProperty workerPoolSize = DynamicPropertyFactory.getInstance().getIntProperty(ServiceRegistryConfig.WORKER_POOL_SIZE, 4);
+    DynamicIntProperty property = DynamicPropertyFactory.getInstance()
+        .getIntProperty(ServiceRegistryConfig.EVENT_LOOP_POOL_SIZE, 4);
+    DynamicIntProperty workerPoolSize = DynamicPropertyFactory.getInstance()
+        .getIntProperty(ServiceRegistryConfig.WORKER_POOL_SIZE, 4);
 
     // 这里面是同步接口,且好像直接在事件线程中用,保险起见,先使用独立的vertx实例
     VertxOptions vertxOptions = new VertxOptions()
-            .setAddressResolverOptions(AddressResolverConfig.getAddressResover(ServiceRegistryConfig.SSL_KEY))
-            .setEventLoopPoolSize(property.get());
+        .setAddressResolverOptions(AddressResolverConfig.getAddressResover(ServiceRegistryConfig.SSL_KEY))
+        .setEventLoopPoolSize(property.get());
     Vertx vertx = VertxUtils.getOrCreateVertxByName("registry", vertxOptions);
-    HttpClientOptions httpClientOptions = createHttpClientOptions();
     clientMgr = new ClientPoolManager<>(vertx, new HttpClientPoolFactory(httpClientOptions));
 
     DeploymentOptions deployOptions = VertxUtils.createClientDeployOptions(this.clientMgr,
-            ServiceRegistryConfig.INSTANCE.getInstances())
-            .setWorker(isWorker())
-            .setWorkerPoolName(ServiceRegistryConfig.WORKER_POOL_NAME)
-            .setWorkerPoolSize(workerPoolSize.get());
+        ServiceRegistryConfig.INSTANCE.getInstances())
+        .setWorker(isWorker())
+        .setWorkerPoolName(ServiceRegistryConfig.WORKER_POOL_NAME)
+        .setWorkerPoolSize(workerPoolSize.get());
     try {
       VertxUtils.blockDeploy(vertx, ClientVerticle.class, deployOptions);
     } catch (InterruptedException e) {
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ClientPool.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ClientPool.java
index e5db559..3784d98 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ClientPool.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ClientPool.java
@@ -19,15 +19,11 @@ package org.apache.servicecomb.serviceregistry.client.http;
 
 import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext;
 
-import io.vertx.core.http.HttpClientOptions;
-
 /**
  * Created by on 2017/4/28.
  */
-public interface ClientPool {
+interface ClientPool {
   void create();
 
-  HttpClientOptions createHttpClientOptions();
-
   HttpClientWithContext getClient();
 }
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/HttpClientPool.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/HttpClientPool.java
index a313669..46ca5ef 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/HttpClientPool.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/HttpClientPool.java
@@ -30,13 +30,21 @@ import io.vertx.core.net.ProxyOptions;
 /**
  * Created by on 2017/4/28.
  */
-public final class HttpClientPool extends AbstractClientPool {
+final class HttpClientPool extends AbstractClientPool {
 
   private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientPool.class);
 
+  /**
+   * The default instance, for default sc cluster.
+   */
   public static final HttpClientPool INSTANCE = new HttpClientPool();
 
   private HttpClientPool() {
+    super(getHttpClientOptionsFromConfigurations(ServiceRegistryConfig.INSTANCE));
+  }
+
+  HttpClientPool(ServiceRegistryConfig serviceRegistryConfig) {
+    super(getHttpClientOptionsFromConfigurations(serviceRegistryConfig));
   }
 
   @Override
@@ -44,26 +52,26 @@ public final class HttpClientPool extends AbstractClientPool {
     return false;
   }
 
-  @Override
-  public HttpClientOptions createHttpClientOptions() {
-    HttpVersion ver = ServiceRegistryConfig.INSTANCE.getHttpVersion();
+  static HttpClientOptions getHttpClientOptionsFromConfigurations(ServiceRegistryConfig serviceRegistryConfig) {
+    HttpVersion ver = serviceRegistryConfig.getHttpVersion();
     HttpClientOptions httpClientOptions = new HttpClientOptions();
     httpClientOptions.setProtocolVersion(ver);
-    httpClientOptions.setConnectTimeout(ServiceRegistryConfig.INSTANCE.getConnectionTimeout());
-    httpClientOptions.setIdleTimeout(ServiceRegistryConfig.INSTANCE.getIdleConnectionTimeout());
-    if (ServiceRegistryConfig.INSTANCE.isProxyEnable()) {
+    httpClientOptions.setConnectTimeout(serviceRegistryConfig.getConnectionTimeout());
+    httpClientOptions.setIdleTimeout(serviceRegistryConfig.getIdleConnectionTimeout());
+    if (serviceRegistryConfig.isProxyEnable()) {
       ProxyOptions proxy = new ProxyOptions();
-      proxy.setHost(ServiceRegistryConfig.INSTANCE.getProxyHost());
-      proxy.setPort(ServiceRegistryConfig.INSTANCE.getProxyPort());
-      proxy.setUsername(ServiceRegistryConfig.INSTANCE.getProxyUsername());
-      proxy.setPassword(Encryptions.decode(ServiceRegistryConfig.INSTANCE.getProxyPasswd(), ServiceRegistryConfig.PROXY_KEY));
+      proxy.setHost(serviceRegistryConfig.getProxyHost());
+      proxy.setPort(serviceRegistryConfig.getProxyPort());
+      proxy.setUsername(serviceRegistryConfig.getProxyUsername());
+      proxy.setPassword(
+          Encryptions.decode(serviceRegistryConfig.getProxyPasswd(), ServiceRegistryConfig.PROXY_KEY));
       httpClientOptions.setProxyOptions(proxy);
     }
     if (ver == HttpVersion.HTTP_2) {
       LOGGER.debug("service center client protocol version is HTTP/2");
       httpClientOptions.setHttp2ClearTextUpgrade(false);
     }
-    if (ServiceRegistryConfig.INSTANCE.isSsl()) {
+    if (serviceRegistryConfig.isSsl()) {
       LOGGER.debug("service center client performs requests over TLS");
       VertxTLSBuilder.buildHttpClientOptions(ServiceRegistryConfig.SSL_KEY, httpClientOptions);
     }
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientPool.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientPool.java
index 2c96f5b..802867a 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientPool.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/WebsocketClientPool.java
@@ -35,6 +35,11 @@ public final class WebsocketClientPool extends AbstractClientPool {
   public static final WebsocketClientPool INSTANCE = new WebsocketClientPool();
 
   private WebsocketClientPool() {
+    super(getHttpClientOptionsFromConfigurations(ServiceRegistryConfig.INSTANCE));
+  }
+
+  WebsocketClientPool(ServiceRegistryConfig serviceRegistryConfig) {
+    super(getHttpClientOptionsFromConfigurations(serviceRegistryConfig));
   }
 
   @Override
@@ -42,18 +47,17 @@ public final class WebsocketClientPool extends AbstractClientPool {
     return true;
   }
 
-  @Override
-  public HttpClientOptions createHttpClientOptions() {
-    HttpVersion ver = ServiceRegistryConfig.INSTANCE.getHttpVersion();
+  static HttpClientOptions getHttpClientOptionsFromConfigurations(ServiceRegistryConfig serviceRegistryConfig) {
+    HttpVersion ver = serviceRegistryConfig.getHttpVersion();
     HttpClientOptions httpClientOptions = new HttpClientOptions();
     httpClientOptions.setProtocolVersion(ver);
-    httpClientOptions.setConnectTimeout(ServiceRegistryConfig.INSTANCE.getConnectionTimeout());
-    httpClientOptions.setIdleTimeout(ServiceRegistryConfig.INSTANCE.getIdleWatchTimeout());
+    httpClientOptions.setConnectTimeout(serviceRegistryConfig.getConnectionTimeout());
+    httpClientOptions.setIdleTimeout(serviceRegistryConfig.getIdleWatchTimeout());
     if (ver == HttpVersion.HTTP_2) {
       LOGGER.debug("service center ws client protocol version is HTTP/2");
       httpClientOptions.setHttp2ClearTextUpgrade(false);
     }
-    if (ServiceRegistryConfig.INSTANCE.isSsl()) {
+    if (serviceRegistryConfig.isSsl()) {
       LOGGER.debug("service center ws client performs requests over TLS");
       VertxTLSBuilder.buildHttpClientOptions(ServiceRegistryConfig.SSL_KEY, httpClientOptions);
     }
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestHttpClientPool.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestHttpClientPool.java
index 1947141..ba74331 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestHttpClientPool.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestHttpClientPool.java
@@ -46,7 +46,8 @@ public class TestHttpClientPool {
     ArchaiusUtils.setProperty(ServiceRegistryConfig.PROXY_USERNAME, "user");
     ArchaiusUtils.setProperty(ServiceRegistryConfig.PROXY_PASSWD, "pass");
 
-    HttpClientOptions httpClientOptions = HttpClientPool.INSTANCE.createHttpClientOptions();
+    HttpClientOptions httpClientOptions = HttpClientPool.getHttpClientOptionsFromConfigurations(
+        ServiceRegistryConfig.buildFromConfiguration());
 
     Assert.assertEquals(
         "{"
@@ -63,7 +64,8 @@ public class TestHttpClientPool {
   public void createHttpClientOptions_noProxy() {
     ArchaiusUtils.setProperty(ServiceRegistryConfig.PROXY_ENABLE, "false");
 
-    HttpClientOptions httpClientOptions = HttpClientPool.INSTANCE.createHttpClientOptions();
+    HttpClientOptions httpClientOptions = HttpClientPool.getHttpClientOptionsFromConfigurations(
+        ServiceRegistryConfig.buildFromConfiguration());
 
     Assert.assertNull(httpClientOptions.getProxyOptions());
   }
@@ -72,7 +74,8 @@ public class TestHttpClientPool {
   public void createHttpClientOptions_http2() {
     ArchaiusUtils.setProperty("servicecomb.service.registry.client.httpVersion", HttpVersion.HTTP_2.name());
 
-    HttpClientOptions httpClientOptions = HttpClientPool.INSTANCE.createHttpClientOptions();
+    HttpClientOptions httpClientOptions = HttpClientPool.getHttpClientOptionsFromConfigurations(
+        ServiceRegistryConfig.buildFromConfiguration());
 
     Assert.assertEquals(HttpVersion.HTTP_2, httpClientOptions.getProtocolVersion());
     Assert.assertFalse(httpClientOptions.isHttp2ClearTextUpgrade());
@@ -80,7 +83,8 @@ public class TestHttpClientPool {
 
   @Test
   public void createHttpClientOptions_notHttp2() {
-    HttpClientOptions httpClientOptions = HttpClientPool.INSTANCE.createHttpClientOptions();
+    HttpClientOptions httpClientOptions = HttpClientPool.getHttpClientOptionsFromConfigurations(
+        ServiceRegistryConfig.buildFromConfiguration());
 
     Assert.assertEquals(HttpVersion.HTTP_1_1, httpClientOptions.getProtocolVersion());
     Assert.assertTrue(httpClientOptions.isHttp2ClearTextUpgrade());
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestWebsocketClientPool.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestWebsocketClientPool.java
index 1badce3..9ac4039 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestWebsocketClientPool.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestWebsocketClientPool.java
@@ -17,6 +17,7 @@
 package org.apache.servicecomb.serviceregistry.client.http;
 
 import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
+import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -40,7 +41,8 @@ public class TestWebsocketClientPool {
   public void createHttpClientOptions_http2() {
     ArchaiusUtils.setProperty("servicecomb.service.registry.client.httpVersion", HttpVersion.HTTP_2.name());
 
-    HttpClientOptions httpClientOptions = WebsocketClientPool.INSTANCE.createHttpClientOptions();
+    HttpClientOptions httpClientOptions = WebsocketClientPool.getHttpClientOptionsFromConfigurations(
+        ServiceRegistryConfig.buildFromConfiguration());
 
     Assert.assertEquals(HttpVersion.HTTP_2, httpClientOptions.getProtocolVersion());
     Assert.assertFalse(httpClientOptions.isHttp2ClearTextUpgrade());
@@ -48,7 +50,8 @@ public class TestWebsocketClientPool {
 
   @Test
   public void createHttpClientOptions_notHttp2() {
-    HttpClientOptions httpClientOptions = WebsocketClientPool.INSTANCE.createHttpClientOptions();
+    HttpClientOptions httpClientOptions = WebsocketClientPool.getHttpClientOptionsFromConfigurations(
+        ServiceRegistryConfig.buildFromConfiguration());
 
     Assert.assertEquals(HttpVersion.HTTP_1_1, httpClientOptions.getProtocolVersion());
     Assert.assertTrue(httpClientOptions.isHttp2ClearTextUpgrade());


[servicecomb-java-chassis] 11/19: [SCB-1691] RegistryUtils manage multiple ServiceRegistry instances

Posted by ya...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

yaohaishi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit 7828f7fbe923d42c78cab79d2ab78ed85033f9c0
Author: yhs0092 <yh...@163.com>
AuthorDate: Tue Feb 11 00:17:51 2020 +0800

    [SCB-1691] RegistryUtils manage multiple ServiceRegistry instances
---
 .../loadbalance/TestLoadBalanceHandler2.java       |  18 ++--
 .../servicecomb/serviceregistry/RegistryUtils.java | 120 +++++++++++++++++++--
 .../cache/MicroserviceInstanceCache.java           |   8 +-
 .../serviceregistry/MockMicroserviceVersions.java  |   8 ++
 .../servicecomb/serviceregistry/TestConsumers.java |  17 ---
 .../servicecomb/serviceregistry/TestRegistry.java  |   9 +-
 .../serviceregistry/TestRegistryBase.java          |  24 ++---
 .../cache/TestMicroserviceInstanceCache.java       |  35 ++++--
 .../instance/TestInstanceCacheChecker.java         |   2 +-
 .../springboot/common/AbstractDiscoveryClient.java |  26 ++---
 10 files changed, 191 insertions(+), 76 deletions(-)

diff --git a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceHandler2.java b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceHandler2.java
index 2edc5bd..36ee88a 100644
--- a/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceHandler2.java
+++ b/handlers/handler-loadbalance/src/test/java/org/apache/servicecomb/loadbalance/TestLoadBalanceHandler2.java
@@ -119,7 +119,7 @@ public class TestLoadBalanceHandler2 {
     Invocation invocation = new Invocation(referenceConfig, operationMeta, new HashMap<>());
 
     InstanceCacheManager instanceCacheManager = Mockito.mock(InstanceCacheManager.class);
-    ServiceRegistry serviceRegistry = Mockito.mock(ServiceRegistry.class);
+    ServiceRegistry serviceRegistry = mockUpServiceRegistry();
     TransportManager transportManager = Mockito.mock(TransportManager.class);
     Transport transport = Mockito.mock(Transport.class);
     ArchaiusUtils.setProperty("servicecomb.loadbalance.filter.operation.enabled", "false");
@@ -268,7 +268,7 @@ public class TestLoadBalanceHandler2 {
     Invocation invocation = new Invocation(referenceConfig, operationMeta, new HashMap<>());
 
     InstanceCacheManager instanceCacheManager = Mockito.mock(InstanceCacheManager.class);
-    ServiceRegistry serviceRegistry = Mockito.mock(ServiceRegistry.class);
+    ServiceRegistry serviceRegistry = mockUpServiceRegistry();
     TransportManager transportManager = Mockito.mock(TransportManager.class);
     Transport transport = Mockito.mock(Transport.class);
     ArchaiusUtils.setProperty("servicecomb.loadbalance.filter.operation.enabled", "false");
@@ -357,7 +357,7 @@ public class TestLoadBalanceHandler2 {
     Invocation invocation = new Invocation(referenceConfig, operationMeta, new HashMap<>());
 
     InstanceCacheManager instanceCacheManager = Mockito.mock(InstanceCacheManager.class);
-    ServiceRegistry serviceRegistry = Mockito.mock(ServiceRegistry.class);
+    ServiceRegistry serviceRegistry = mockUpServiceRegistry();
     TransportManager transportManager = Mockito.mock(TransportManager.class);
     Transport transport = Mockito.mock(Transport.class);
     ArchaiusUtils.setProperty("servicecomb.loadbalance.filter.operation.enabled", "false");
@@ -484,7 +484,7 @@ public class TestLoadBalanceHandler2 {
     });
 
     InstanceCacheManager instanceCacheManager = Mockito.mock(InstanceCacheManager.class);
-    ServiceRegistry serviceRegistry = Mockito.mock(ServiceRegistry.class);
+    ServiceRegistry serviceRegistry = mockUpServiceRegistry();
     TransportManager transportManager = Mockito.mock(TransportManager.class);
     Transport transport = Mockito.mock(Transport.class);
     ArchaiusUtils.setProperty("servicecomb.loadbalance.filter.operation.enabled", "false");
@@ -627,7 +627,7 @@ public class TestLoadBalanceHandler2 {
     });
 
     InstanceCacheManager instanceCacheManager = Mockito.mock(InstanceCacheManager.class);
-    ServiceRegistry serviceRegistry = Mockito.mock(ServiceRegistry.class);
+    ServiceRegistry serviceRegistry = mockUpServiceRegistry();
     TransportManager transportManager = Mockito.mock(TransportManager.class);
     Transport transport = Mockito.mock(Transport.class);
     ArchaiusUtils.setProperty("servicecomb.loadbalance.filter.operation.enabled", "false");
@@ -778,7 +778,7 @@ public class TestLoadBalanceHandler2 {
     AsyncResponse asyncResp = Mockito.mock(AsyncResponse.class);
 
     InstanceCacheManager instanceCacheManager = Mockito.mock(InstanceCacheManager.class);
-    ServiceRegistry serviceRegistry = Mockito.mock(ServiceRegistry.class);
+    ServiceRegistry serviceRegistry = mockUpServiceRegistry();
     TransportManager transportManager = Mockito.mock(TransportManager.class);
     Transport transport = Mockito.mock(Transport.class);
     ArchaiusUtils.setProperty("servicecomb.loadbalance.filter.operation.enabled", "false");
@@ -992,4 +992,10 @@ public class TestLoadBalanceHandler2 {
       }
     };
   }
+
+  private ServiceRegistry mockUpServiceRegistry() {
+    ServiceRegistry serviceRegistry = Mockito.mock(ServiceRegistry.class);
+    when(serviceRegistry.getEventBus()).thenReturn(EventManager.getEventBus());
+    return serviceRegistry;
+  }
 }
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
index 2f93bd6..49f28e2 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/RegistryUtils.java
@@ -21,14 +21,18 @@ import java.net.InetSocketAddress;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.regex.Matcher;
 
 import org.apache.http.client.utils.URIBuilder;
 import org.apache.servicecomb.config.ConfigUtil;
 import org.apache.servicecomb.config.archaius.sources.MicroserviceConfigLoader;
+import org.apache.servicecomb.foundation.common.Holder;
 import org.apache.servicecomb.foundation.common.event.EventManager;
 import org.apache.servicecomb.foundation.common.net.IpPort;
 import org.apache.servicecomb.foundation.common.net.NetUtils;
@@ -43,7 +47,10 @@ import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
 import org.apache.servicecomb.serviceregistry.consumer.AppManager;
 import org.apache.servicecomb.serviceregistry.definition.MicroserviceDefinition;
 import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryFactory;
+import org.apache.servicecomb.serviceregistry.registry.cache.AggregateServiceRegistryCache;
 import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache;
+import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCache.MicroserviceCacheStatus;
+import org.apache.servicecomb.serviceregistry.registry.cache.MicroserviceCacheKey;
 import org.apache.servicecomb.serviceregistry.swagger.SwaggerLoader;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -55,6 +62,9 @@ import com.netflix.config.DynamicPropertyFactory;
 public final class RegistryUtils {
   private static final Logger LOGGER = LoggerFactory.getLogger(RegistryUtils.class);
 
+  /**
+   * The default ServiceRegistry instance
+   */
   private static volatile ServiceRegistry serviceRegistry;
 
   // value is ip or {interface name}
@@ -68,6 +78,12 @@ public final class RegistryUtils {
 
   private static InstanceCacheManager instanceCacheManager = new InstanceCacheManagerNew(appManager);
 
+  private static final Map<String, ServiceRegistryConfig> EXTRA_SERVICE_REGISTRY_CONFIGS = new LinkedHashMap<>();
+
+  private static final Map<String, ServiceRegistry> EXTRA_SERVICE_REGISTRIES = new LinkedHashMap<>();
+
+  static AggregateServiceRegistryCache aggregateServiceRegistryCache;
+
   private RegistryUtils() {
   }
 
@@ -78,18 +94,43 @@ public final class RegistryUtils {
 
     MicroserviceConfigLoader loader = ConfigUtil.getMicroserviceConfigLoader();
     MicroserviceDefinition microserviceDefinition = new MicroserviceDefinition(loader.getConfigModels());
+    initializeServiceRegistries(microserviceDefinition);
+
+    initAggregateServiceRegistryCache();
+  }
+
+  private static void initAggregateServiceRegistryCache() {
+    ArrayList<ServiceRegistry> serviceRegistries = new ArrayList<>();
+    executeOnEachServiceRegistry(serviceRegistries::add);
+    aggregateServiceRegistryCache = new AggregateServiceRegistryCache(serviceRegistries);
+    aggregateServiceRegistryCache.setCacheRefreshedWatcher(refreshedCaches -> {
+      appManager.pullInstances();
+    });
+
+    executeOnEachServiceRegistry(
+        serviceRegistry -> serviceRegistry
+            .getEventBus()
+            .register(aggregateServiceRegistryCache));
+  }
+
+  private static void initializeServiceRegistries(MicroserviceDefinition microserviceDefinition) {
     serviceRegistry =
         ServiceRegistryFactory
             .create(EventManager.eventBus, ServiceRegistryConfig.INSTANCE, microserviceDefinition);
-    serviceRegistry.init();
+    EXTRA_SERVICE_REGISTRY_CONFIGS.forEach((k, v) -> {
+      ServiceRegistry serviceRegistry = ServiceRegistryFactory
+          .create(EventManager.getEventBus(), v, microserviceDefinition);
+      addExtraServiceRegistry(serviceRegistry);
+    });
+    executeOnEachServiceRegistry(ServiceRegistry::init);
   }
 
   public static void run() {
-    serviceRegistry.run();
+    executeOnEachServiceRegistry(ServiceRegistry::run);
   }
 
   public static void destroy() {
-    serviceRegistry.destroy();
+    executeOnEachServiceRegistry(ServiceRegistry::destroy);
   }
 
   /**
@@ -106,8 +147,10 @@ public final class RegistryUtils {
 
   public static void setServiceRegistry(ServiceRegistry serviceRegistry) {
     RegistryUtils.serviceRegistry = serviceRegistry;
+    initAggregateServiceRegistryCache();
   }
 
+  @Deprecated
   public static ServiceRegistryClient getServiceRegistryClient() {
     return serviceRegistry.getServiceRegistryClient();
   }
@@ -236,21 +279,35 @@ public final class RegistryUtils {
 
   public static List<MicroserviceInstance> findServiceInstance(String appId, String serviceName,
       String versionRule) {
-    return serviceRegistry.findServiceInstance(appId, serviceName, versionRule);
+    MicroserviceCache serviceCache = aggregateServiceRegistryCache.findServiceCache(
+        MicroserviceCacheKey.builder()
+            .appId(appId).serviceName(serviceName).env(getMicroservice().getEnvironment())
+            .build()
+    );
+    return MicroserviceCacheStatus.SERVICE_NOT_FOUND.equals(serviceCache.getStatus()) ?
+        null : serviceCache.getInstances();
   }
 
   // update microservice instance properties
   public static boolean updateInstanceProperties(Map<String, String> instanceProperties) {
-    return serviceRegistry.updateInstanceProperties(instanceProperties);
+    Holder<Boolean> resultHolder = new Holder<>(true);
+    executeOnEachServiceRegistry(sr -> {
+      boolean updateResult = sr.updateInstanceProperties(instanceProperties);
+      resultHolder.value = updateResult && resultHolder.value;
+    });
+    return resultHolder.value;
   }
 
   public static Microservice getMicroservice(String microserviceId) {
-    return serviceRegistry.getRemoteMicroservice(microserviceId);
+    return getResultFromFirstValidServiceRegistry(sr -> sr.getRemoteMicroservice(microserviceId));
   }
 
   public static MicroserviceInstances findServiceInstances(String appId, String serviceName,
       String versionRule, String revision) {
-    return serviceRegistry.findServiceInstances(appId, serviceName, versionRule, revision);
+    MicroserviceCache serviceCache = aggregateServiceRegistryCache.findServiceCache(
+        MicroserviceCacheKey.builder().appId(appId).serviceName(serviceName).env(getMicroservice().getEnvironment())
+            .build());
+    return convertCacheToMicroserviceInstances(serviceCache);
   }
 
   /**
@@ -288,11 +345,56 @@ public final class RegistryUtils {
   }
 
   public static String getAggregatedSchema(String microserviceId, String schemaId) {
-    return serviceRegistry.getServiceRegistryClient().getAggregatedSchema(microserviceId, schemaId);
+    return getResultFromFirstValidServiceRegistry(
+        sr -> sr.getServiceRegistryClient().getAggregatedSchema(microserviceId, schemaId));
   }
 
   public static Microservice getAggregatedRemoteMicroservice(String microserviceId) {
-    return serviceRegistry.getAggregatedRemoteMicroservice(microserviceId);
+    return getResultFromFirstValidServiceRegistry(
+        sr -> sr.getAggregatedRemoteMicroservice(microserviceId));
+  }
+
+  public static <T> T getResultFromFirstValidServiceRegistry(Function<ServiceRegistry, T> action) {
+    Holder<T> resultHolder = new Holder<>();
+    executeOnEachServiceRegistry(sr -> {
+      if (null == resultHolder.value) {
+        resultHolder.value = action.apply(sr);
+      }
+    });
+    return resultHolder.value;
+  }
+
+  public static void executeOnEachServiceRegistry(Consumer<ServiceRegistry> action) {
+    if (null != getServiceRegistry()) {
+      action.accept(getServiceRegistry());
+    }
+    if (!EXTRA_SERVICE_REGISTRIES.isEmpty()) {
+      EXTRA_SERVICE_REGISTRIES.forEach((k, v) -> action.accept(v));
+    }
+  }
+
+  public static void addExtraServiceRegistry(ServiceRegistry serviceRegistry) {
+    Objects.requireNonNull(serviceRegistry);
+    LOGGER.info("extra ServiceRegistry added: [{}], [{}]", serviceRegistry.getName(), serviceRegistry.getClass());
+    EXTRA_SERVICE_REGISTRIES.put(serviceRegistry.getName(), serviceRegistry);
+  }
+
+  /**
+   * Add the configuration object of {@link ServiceRegistry}.
+   * The corresponding {@link ServiceRegistry} instances are instantiated later in {@link #init()}
+   */
+  public static void addExtraServiceRegistryConfig(ServiceRegistryConfig serviceRegistryConfig) {
+    validateRegistryConfig(serviceRegistryConfig);
+    EXTRA_SERVICE_REGISTRY_CONFIGS.put(serviceRegistryConfig.getRegistryName(), serviceRegistryConfig);
+  }
+
+  /**
+   * @throws NullPointerException serviceRegistryConfig is null
+   * @throws IllegalArgumentException config value is illegal
+   */
+  public static void validateRegistryConfig(ServiceRegistryConfig serviceRegistryConfig) {
+    Objects.requireNonNull(serviceRegistryConfig);
+    validateRegistryName(serviceRegistryConfig.getRegistryName());
   }
 
   /**
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/MicroserviceInstanceCache.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/MicroserviceInstanceCache.java
index 16a0381..80c8fb5 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/MicroserviceInstanceCache.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/cache/MicroserviceInstanceCache.java
@@ -52,7 +52,7 @@ public class MicroserviceInstanceCache {
   public static Microservice getOrCreate(String serviceId) {
     try {
       return microservices.get(serviceId, () -> {
-        Microservice microservice = RegistryUtils.getServiceRegistryClient().getAggregatedMicroservice(serviceId);
+        Microservice microservice = RegistryUtils.getAggregatedRemoteMicroservice(serviceId);
         if (microservice == null) {
           throw new IllegalArgumentException("service id not exists.");
         }
@@ -70,9 +70,9 @@ public class MicroserviceInstanceCache {
       return instances.get(key, new Callable<MicroserviceInstance>() {
 
         @Override
-        public MicroserviceInstance call() throws Exception {
-          MicroserviceInstance instance = RegistryUtils.getServiceRegistryClient()
-              .findServiceInstance(serviceId, instanceId);
+        public MicroserviceInstance call() {
+          MicroserviceInstance instance = RegistryUtils.getResultFromFirstValidServiceRegistry(
+              sr -> sr.getServiceRegistryClient().findServiceInstance(serviceId, instanceId));
           if (instance == null) {
             throw new IllegalArgumentException("instance id not exists.");
           }
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/MockMicroserviceVersions.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/MockMicroserviceVersions.java
index 3d183b1..b7dc262 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/MockMicroserviceVersions.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/MockMicroserviceVersions.java
@@ -24,6 +24,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 
+import org.apache.servicecomb.foundation.common.event.EventManager;
 import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
 import org.apache.servicecomb.serviceregistry.consumer.AppManager;
@@ -34,6 +35,8 @@ import org.apache.servicecomb.serviceregistry.version.Version;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
 
+import com.google.common.eventbus.EventBus;
+
 import mockit.Mock;
 import mockit.MockUp;
 
@@ -51,6 +54,11 @@ public class MockMicroserviceVersions extends MicroserviceVersions {
       Microservice getAggregatedRemoteMicroservice(String microserviceId) {
         return mockedMicroservices.get(microserviceId);
       }
+
+      @Mock
+      EventBus getEventBus() {
+        return EventManager.getEventBus();
+      }
     }.getMockInstance();
 
     RegistryUtils.setServiceRegistry(serviceRegistry);
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestConsumers.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestConsumers.java
index b5c009c..0aead31 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestConsumers.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestConsumers.java
@@ -71,23 +71,6 @@ public class TestConsumers extends TestRegistryBase {
     MicroserviceInstanceChangedEvent event = new MicroserviceInstanceChangedEvent();
     event.setKey(key);
 
-    // not match
-    key.setAppId(appId + "1");
-    key.setServiceName(serviceName + "1");
-    eventBus.post(event);
-    Assert.assertEquals(1, microserviceManager.getVersionsByName().size());
-
-    key.setAppId(appId + "1");
-    key.setServiceName(serviceName);
-    eventBus.post(event);
-    Assert.assertEquals(1, microserviceManager.getVersionsByName().size());
-
-    key.setAppId(appId);
-    key.setServiceName(serviceName + "1");
-    eventBus.post(event);
-    Assert.assertEquals(1, microserviceManager.getVersionsByName().size());
-
-    // match
     key.setAppId(appId);
     key.setServiceName(serviceName);
     eventBus.post(event);
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistry.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistry.java
index 63d1d8b..af713bc 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistry.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistry.java
@@ -22,7 +22,7 @@ import static org.apache.servicecomb.serviceregistry.RegistryUtils.PUBLISH_ADDRE
 import java.net.InetAddress;
 import java.net.URI;
 import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -79,6 +79,7 @@ public class TestRegistry {
     inMemoryConfig.clear();
   }
 
+  @SuppressWarnings("deprecation")
   @Test
   public void testDelegate() {
     ServiceRegistry serviceRegistry = ServiceRegistryFactory.createLocal();
@@ -99,7 +100,7 @@ public class TestRegistry {
     Assert.assertEquals(RegistryUtils.getMicroservice().getServiceId(), instanceList.get(0).getServiceId());
 
     instanceList = RegistryUtils.findServiceInstance("default", "notExists", "0.0.1");
-    Assert.assertEquals(null, instanceList);
+    Assert.assertNull(instanceList);
 
     MicroserviceInstances microserviceInstances =
         RegistryUtils.findServiceInstances("default", "default", "0.0.1", "0");
@@ -193,7 +194,7 @@ public class TestRegistry {
     };
 
     Assert.assertEquals("rest://172.0.0.0:8080", RegistryUtils.getPublishAddress("rest", "172.0.0.0:8080"));
-    Assert.assertEquals(null, RegistryUtils.getPublishAddress("rest", null));
+    Assert.assertNull(RegistryUtils.getPublishAddress("rest", null));
 
     URI uri = new URI(RegistryUtils.getPublishAddress("rest", "0.0.0.0:8080"));
     Assert.assertEquals("1.1.1.1:8080", uri.getAuthority());
@@ -224,7 +225,7 @@ public class TestRegistry {
         };
       }
     };
-    String query = URLEncodedUtils.format(Arrays.asList(new BasicNameValuePair("country", "中 国")),
+    String query = URLEncodedUtils.format(Collections.singletonList(new BasicNameValuePair("country", "中 国")),
         StandardCharsets.UTF_8.name());
     Assert.assertEquals("rest://1.1.1.1:8080?" + query,
         RegistryUtils.getPublishAddress("rest", "172.0.0.0:8080?" + query));
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistryBase.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistryBase.java
index 267af9c..88f63e2 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistryBase.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/TestRegistryBase.java
@@ -22,7 +22,6 @@ import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
 import org.apache.servicecomb.serviceregistry.client.http.MicroserviceInstances;
 import org.apache.servicecomb.serviceregistry.consumer.AppManager;
 import org.apache.servicecomb.serviceregistry.consumer.MicroserviceManager;
-import org.apache.servicecomb.serviceregistry.definition.DefinitionConst;
 import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryFactory;
 import org.junit.AfterClass;
 import org.junit.Before;
@@ -30,7 +29,8 @@ import org.junit.Before;
 import com.google.common.eventbus.EventBus;
 
 import mockit.Deencapsulation;
-import mockit.Expectations;
+import mockit.Mock;
+import mockit.MockUp;
 
 public class TestRegistryBase {
   protected ServiceRegistry serviceRegistry;
@@ -88,21 +88,21 @@ public class TestRegistryBase {
   protected void mockNotExist() {
     MicroserviceInstances microserviceInstances = new MicroserviceInstances();
     microserviceInstances.setMicroserviceNotExist(true);
-    new Expectations(RegistryUtils.getServiceRegistry()) {
-      {
-        RegistryUtils.getServiceRegistry()
-            .findServiceInstances(anyString, anyString, DefinitionConst.VERSION_RULE_ALL, anyString);
-        result = microserviceInstances;
+    new MockUp<RegistryUtils>() {
+      @Mock
+      MicroserviceInstances findServiceInstances(String appId, String serviceName,
+          String versionRule, String revision) {
+        return microserviceInstances;
       }
     };
   }
 
   protected void mockDisconnect() {
-    new Expectations(RegistryUtils.getServiceRegistry()) {
-      {
-        RegistryUtils.getServiceRegistry()
-            .findServiceInstances(anyString, anyString, DefinitionConst.VERSION_RULE_ALL, anyString);
-        result = null;
+    new MockUp<RegistryUtils>() {
+      @Mock
+      MicroserviceInstances findServiceInstances(String appId, String serviceName,
+          String versionRule, String revision) {
+        return null;
       }
     };
   }
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/cache/TestMicroserviceInstanceCache.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/cache/TestMicroserviceInstanceCache.java
index 85da7fb..0e31341 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/cache/TestMicroserviceInstanceCache.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/cache/TestMicroserviceInstanceCache.java
@@ -18,6 +18,7 @@
 package org.apache.servicecomb.serviceregistry.cache;
 
 import org.apache.servicecomb.serviceregistry.RegistryUtils;
+import org.apache.servicecomb.serviceregistry.ServiceRegistry;
 import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
 import org.apache.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
 import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient;
@@ -25,20 +26,25 @@ import org.junit.Assert;
 import org.junit.Test;
 
 import mockit.Expectations;
+import mockit.Mock;
+import mockit.MockUp;
 import mockit.Mocked;
 
 public class TestMicroserviceInstanceCache {
   @Test
-  public void testGetOrCreateMicroservice(@Mocked RegistryUtils utils, @Mocked ServiceRegistryClient client,
+  public void testGetOrCreateMicroservice(@Mocked ServiceRegistry serviceRegistry,
+      @Mocked ServiceRegistryClient client,
       @Mocked Microservice microservice) {
-    new Expectations() {
-      {
-        RegistryUtils.getServiceRegistryClient();
-        result = client;
-        client.getAggregatedMicroservice("forkedid");
-        result = microservice;
-        client.getAggregatedMicroservice("forkedidNull");
-        result = null;
+    new MockUp<RegistryUtils>() {
+      @Mock
+      Microservice getAggregatedRemoteMicroservice(String microserviceId) {
+        if ("forkedid".equals(microserviceId)) {
+          return microservice;
+        }
+        if ("forkedidNull".equals(microserviceId)) {
+          return null;
+        }
+        throw new IllegalArgumentException("unrecognized param");
       }
     };
     Microservice cachedService = MicroserviceInstanceCache.getOrCreate("forkedid");
@@ -50,11 +56,18 @@ public class TestMicroserviceInstanceCache {
   }
 
   @Test
-  public void testGetOrCreateMicroserviceInstance(@Mocked RegistryUtils utils, @Mocked ServiceRegistryClient client,
+  public void testGetOrCreateMicroserviceInstance(@Mocked ServiceRegistry serviceRegistry,
+      @Mocked ServiceRegistryClient client,
       @Mocked MicroserviceInstance instance) {
+    new MockUp<RegistryUtils>() {
+      @Mock
+      ServiceRegistry getServiceRegistry() {
+        return serviceRegistry;
+      }
+    };
     new Expectations() {
       {
-        RegistryUtils.getServiceRegistryClient();
+        serviceRegistry.getServiceRegistryClient();
         result = client;
         client.findServiceInstance("forkedserviceid", "forkedinstanceid");
         result = instance;
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheChecker.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheChecker.java
index 133535c..cafae79 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheChecker.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/diagnosis/instance/TestInstanceCacheChecker.java
@@ -177,7 +177,7 @@ public class TestInstanceCacheChecker {
   public void check_findInstances_revisionNotMatch() {
     Holder<MicroserviceInstances> findHolder = createFindServiceInstancesResult();
 
-    new MockUp<ServiceRegistry>(serviceRegistry) {
+    new MockUp<RegistryUtils>() {
       @Mock
       MicroserviceInstances findServiceInstances(String appId, String serviceName,
           String versionRule, String revision) {
diff --git a/spring-boot/spring-boot-common/src/main/java/org/apache/servicecomb/springboot/common/AbstractDiscoveryClient.java b/spring-boot/spring-boot-common/src/main/java/org/apache/servicecomb/springboot/common/AbstractDiscoveryClient.java
index f114439..77b0daa 100644
--- a/spring-boot/spring-boot-common/src/main/java/org/apache/servicecomb/springboot/common/AbstractDiscoveryClient.java
+++ b/spring-boot/spring-boot-common/src/main/java/org/apache/servicecomb/springboot/common/AbstractDiscoveryClient.java
@@ -17,14 +17,15 @@
 package org.apache.servicecomb.springboot.common;
 
 import java.util.ArrayList;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.servicecomb.foundation.common.cache.VersionedCache;
 import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx;
 import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.serviceregistry.api.registry.Microservice;
-import org.apache.servicecomb.serviceregistry.client.ServiceRegistryClient;
 import org.apache.servicecomb.serviceregistry.definition.DefinitionConst;
 import org.apache.servicecomb.serviceregistry.discovery.DiscoveryContext;
 import org.apache.servicecomb.serviceregistry.discovery.DiscoveryFilter;
@@ -33,9 +34,10 @@ import org.apache.servicecomb.serviceregistry.discovery.DiscoveryTree;
 public abstract class AbstractDiscoveryClient {
 
   private Map<String, DiscoveryTree> discoveryTrees = new ConcurrentHashMapEx<>();
-  private DiscoveryFilter filter = null;
 
-  public AbstractDiscoveryClient(DiscoveryFilter filter){
+  private DiscoveryFilter filter;
+
+  public AbstractDiscoveryClient(DiscoveryFilter filter) {
     this.filter = filter;
   }
 
@@ -44,7 +46,7 @@ public abstract class AbstractDiscoveryClient {
     context.setInputParameters(serviceId);
 
     DiscoveryTree discoveryTree = discoveryTrees.computeIfAbsent(serviceId, key -> {
-      DiscoveryTree tree =  new DiscoveryTree();
+      DiscoveryTree tree = new DiscoveryTree();
       tree.addFilter(filter);
       return tree;
     });
@@ -58,14 +60,14 @@ public abstract class AbstractDiscoveryClient {
   }
 
   public List<String> getServices() {
-    ServiceRegistryClient client = RegistryUtils.getServiceRegistryClient();
-    List<Microservice> services = client.getAllMicroservices();
-    List<String> serviceIDList = new ArrayList<>();
-    if (null != services && !services.isEmpty()) {
-      for (Microservice service : services) {
-        serviceIDList.add(service.getServiceName());
+    Set<String> uniqueServiceNames = new LinkedHashSet<>();
+    RegistryUtils.executeOnEachServiceRegistry(sr -> {
+      List<Microservice> allMicroservices = sr.getServiceRegistryClient().getAllMicroservices();
+      if (null == allMicroservices || allMicroservices.isEmpty()) {
+        return;
       }
-    }
-    return serviceIDList;
+      allMicroservices.forEach(ms -> uniqueServiceNames.add(ms.getServiceName()));
+    });
+    return new ArrayList<>(uniqueServiceNames);
   }
 }