diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java index f3cc97358e..5977a8b529 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java @@ -52,6 +52,7 @@ import static java.util.Collections.emptySet; import static java.util.Collections.unmodifiableSet; import static java.util.stream.Collectors.toSet; import static java.util.stream.Stream.of; +import static org.apache.dubbo.common.constants.CommonConstants.CHECK_KEY; import static org.apache.dubbo.common.constants.CommonConstants.DUBBO; import static org.apache.dubbo.common.constants.CommonConstants.GROUP_CHAR_SEPARATOR; import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; @@ -259,10 +260,13 @@ public class ServiceDiscoveryRegistry implements Registry { public void doSubscribe(URL url, NotifyListener listener) { writableMetadataService.subscribeURL(url); + boolean check = url.getParameter(CHECK_KEY, false); Set serviceNames = getServices(url, listener); if (CollectionUtils.isEmpty(serviceNames)) { - throw new IllegalStateException("Should has at least one way to know which services this interface belongs to, subscription url: " + url); + if (check) { + throw new IllegalStateException("Should has at least one way to know which services this interface belongs to, subscription url: " + url); + } } subscribeURLs(url, listener, serviceNames); @@ -388,6 +392,42 @@ public class ServiceDiscoveryRegistry implements Registry { .collect(toSet())); } +// public void doSubscribe(URL url, NotifyListener listener) { +// writableMetadataService.subscribeURL(url); +// +// boolean check = url.getParameter(CHECK_KEY, false); +// Set serviceNames = Collections.emptySet(); +// try { +// serviceNames = getServices(url, listener); +// } catch(ServiceNameMapping.MappingException e) { +// if (!check) { +// startMappingScheduler(url, listener); +// return; +// } +// } +// if (CollectionUtils.isEmpty(serviceNames)) { +// if (check) { +// throw new IllegalStateException("Should has at least one way to know which services this interface belongs to, subscription url: " + url); +// } else { +// return; +// } +// } +// +// subscribeURLs(url, listener, serviceNames); +// } +// +// private void startMappingScheduler(URL url, NotifyListener listener) { +// scheduler.submit(() -> { +// while(true) { +// try { +// Set serviceNames = serviceNameMapping.getAndListen(url); +// } catch (Exception e) { +// +// } +// } +// }); +// } + /** * Get the subscribed service names * @@ -468,12 +508,23 @@ public class ServiceDiscoveryRegistry implements Registry { @Override public void onEvent(MappingChangedEvent event) { Set newApps = event.getApps(); + Set tempOldApps = oldApps; + oldApps = newApps; + if (CollectionUtils.isEmpty(newApps)) { return; } - if (!CollectionUtils.equals(oldApps, newApps) && newApps.size() >= oldApps.size()) { - doUnsubscribe(url, listener); + + if (CollectionUtils.isEmpty(tempOldApps) && newApps.size() > 0) { subscribeURLs(url, listener, newApps); + return; + } + + for (String newAppName : newApps) { + if (!tempOldApps.contains(newAppName)) { + subscribeURLs(url, listener, newApps); + return; + } } } } diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationInvoker.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationInvoker.java index c95dc88185..6aa6f4a89d 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationInvoker.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/migration/MigrationInvoker.java @@ -46,8 +46,8 @@ public class MigrationInvoker implements MigrationClusterInvoker { private Class type; private RegistryProtocol registryProtocol; - private ClusterInvoker invoker; - private ClusterInvoker serviceDiscoveryInvoker; + private volatile ClusterInvoker invoker; + private volatile ClusterInvoker serviceDiscoveryInvoker; private volatile ClusterInvoker currentAvailableInvoker; public MigrationInvoker(RegistryProtocol registryProtocol, @@ -103,13 +103,17 @@ public class MigrationInvoker implements MigrationClusterInvoker { if (!forceMigrate) { refreshServiceDiscoveryInvoker(); refreshInterfaceInvoker(); - // any of the address list changes, compare these two lists. - ((DynamicDirectory) invoker.getDirectory()).addInvokersChangedListener(this::compareAddresses); - ((DynamicDirectory) serviceDiscoveryInvoker.getDirectory()).addInvokersChangedListener(this::compareAddresses); - this.compareAddresses(); + setListener(invoker, () -> { + this.compareAddresses(invoker, serviceDiscoveryInvoker); + }); + setListener(serviceDiscoveryInvoker, () -> { + this.compareAddresses(invoker, serviceDiscoveryInvoker); + }); } else { refreshServiceDiscoveryInvoker(); - destroyInterfaceInvoker(); + setListener(serviceDiscoveryInvoker, () -> { + this.destroyInterfaceInvoker(this.invoker); + }); } } @@ -143,7 +147,9 @@ public class MigrationInvoker implements MigrationClusterInvoker { @Override public synchronized void fallbackToInterfaceInvoker() { refreshInterfaceInvoker(); - destroyServiceDiscoveryInvoker(); + setListener(invoker, () -> { + this.destroyServiceDiscoveryInvoker(this.serviceDiscoveryInvoker); + }); } @Override @@ -231,7 +237,7 @@ public class MigrationInvoker implements MigrationClusterInvoker { private volatile boolean invokersChanged; - private synchronized void compareAddresses() { + private synchronized void compareAddresses(ClusterInvoker serviceDiscoveryInvoker, ClusterInvoker invoker) { this.invokersChanged = true; if (logger.isDebugEnabled()) { logger.info("" + invoker.getDirectory().getAllInvokers().size()); @@ -239,25 +245,28 @@ public class MigrationInvoker implements MigrationClusterInvoker { Set detectors = ExtensionLoader.getExtensionLoader(MigrationAddressComparator.class).getSupportedExtensionInstances(); if (detectors != null && detectors.stream().allMatch(migrationDetector -> migrationDetector.shouldMigrate(serviceDiscoveryInvoker, invoker))) { - discardInterfaceInvokerAddress(); + discardInterfaceInvokerAddress(invoker); } else { - discardServiceDiscoveryInvokerAddress(); + discardServiceDiscoveryInvokerAddress(serviceDiscoveryInvoker); } } - protected synchronized void destroyServiceDiscoveryInvoker() { - this.currentAvailableInvoker = invoker; + protected synchronized void destroyServiceDiscoveryInvoker(ClusterInvoker serviceDiscoveryInvoker) { + if (checkInvokerAvailable(this.invoker)) { + this.currentAvailableInvoker = this.invoker; + } if (serviceDiscoveryInvoker != null) { if (logger.isDebugEnabled()) { logger.debug("Destroying instance address invokers, will not listen for address changes until re-subscribed, " + type.getName()); } serviceDiscoveryInvoker.destroy(); - serviceDiscoveryInvoker = null; } } - protected synchronized void discardServiceDiscoveryInvokerAddress() { - this.currentAvailableInvoker = invoker; + protected synchronized void discardServiceDiscoveryInvokerAddress(ClusterInvoker serviceDiscoveryInvoker) { + if (checkInvokerAvailable(this.invoker)) { + this.currentAvailableInvoker = this.invoker; + } if (serviceDiscoveryInvoker != null) { if (logger.isDebugEnabled()) { logger.debug("Discarding instance addresses, total size " + serviceDiscoveryInvoker.getDirectory().getAllInvokers().size()); @@ -267,6 +276,7 @@ public class MigrationInvoker implements MigrationClusterInvoker { } protected synchronized void refreshServiceDiscoveryInvoker() { + clearListener(serviceDiscoveryInvoker); if (needRefresh(serviceDiscoveryInvoker)) { if (logger.isDebugEnabled()) { logger.debug("Re-subscribing instance addresses, current interface " + type.getName()); @@ -275,7 +285,20 @@ public class MigrationInvoker implements MigrationClusterInvoker { } } + private void clearListener(ClusterInvoker invoker) { + if (invoker == null) return; + DynamicDirectory directory = (DynamicDirectory) invoker.getDirectory(); + directory.setInvokersChangedListener(null); + } + + private void setListener(ClusterInvoker invoker, InvokersChangedListener listener) { + if (invoker == null) return; + DynamicDirectory directory = (DynamicDirectory) invoker.getDirectory(); + directory.setInvokersChangedListener(listener); + } + protected synchronized void refreshInterfaceInvoker() { + clearListener(invoker); if (needRefresh(invoker)) { // FIXME invoker.destroy(); if (logger.isDebugEnabled()) { @@ -285,19 +308,22 @@ public class MigrationInvoker implements MigrationClusterInvoker { } } - protected synchronized void destroyInterfaceInvoker() { - this.currentAvailableInvoker = serviceDiscoveryInvoker; + protected synchronized void destroyInterfaceInvoker(ClusterInvoker invoker) { + if (checkInvokerAvailable(this.serviceDiscoveryInvoker)) { + this.currentAvailableInvoker = this.serviceDiscoveryInvoker; + } if (invoker != null) { if (logger.isDebugEnabled()) { logger.debug("Destroying interface address invokers, will not listen for address changes until re-subscribed, " + type.getName()); } invoker.destroy(); - invoker = null; } } - protected synchronized void discardInterfaceInvokerAddress() { - this.currentAvailableInvoker = serviceDiscoveryInvoker; + protected synchronized void discardInterfaceInvokerAddress(ClusterInvoker invoker) { + if (this.serviceDiscoveryInvoker != null) { + this.currentAvailableInvoker = this.serviceDiscoveryInvoker; + } if (invoker != null) { if (logger.isDebugEnabled()) { logger.debug("Discarding interface addresses, total address size " + invoker.getDirectory().getAllInvokers().size()); diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java index 41e3584b2c..305650687c 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java @@ -38,9 +38,7 @@ import org.apache.dubbo.rpc.cluster.RouterFactory; import org.apache.dubbo.rpc.cluster.directory.AbstractDirectory; import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Set; import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE; import static org.apache.dubbo.common.constants.CommonConstants.DUBBO; @@ -249,7 +247,7 @@ public abstract class DynamicDirectory extends AbstractDirectory implement logger.warn("Failed to destroy service " + serviceKey, t); } - invokersChangedListeners.clear(); + invokersChangedListener = null; } @Override @@ -261,15 +259,23 @@ public abstract class DynamicDirectory extends AbstractDirectory implement } } - private Set invokersChangedListeners = new HashSet<>(); + private volatile InvokersChangedListener invokersChangedListener; + private volatile boolean addressChanged; - public void addInvokersChangedListener(InvokersChangedListener listener) { - invokersChangedListeners.add(listener); + public void setInvokersChangedListener(InvokersChangedListener listener) { + this.invokersChangedListener = listener; + if (addressChanged) { + invokersChangedListener.onChange(); + this.addressChanged = false; + } } protected void invokersChanged() { - for (InvokersChangedListener l : invokersChangedListeners) { - l.onChange(); + if (invokersChangedListener != null) { + invokersChangedListener.onChange(); + this.addressChanged = false; + } else { + this.addressChanged = true; } }