Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.UrlUtils;

import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;

Expand All @@ -41,17 +42,19 @@ public ListenerRegistryWrapper(Registry registry, List<RegistryServiceListener>

@Override
public URL getUrl() {
return registry.getUrl();
return registry == null ? null : registry.getUrl();
}

@Override
public boolean isAvailable() {
return registry.isAvailable();
return registry != null && registry.isAvailable();
}

@Override
public void destroy() {
registry.destroy();
if (registry != null) {
registry.destroy();
}
}

@Override
Expand Down Expand Up @@ -94,20 +97,22 @@ public void subscribe(URL url, NotifyListener listener) {
@Override
public void unsubscribe(URL url, NotifyListener listener) {
try {
registry.unsubscribe(url, listener);
if (registry != null) {
registry.unsubscribe(url, listener);
}
} finally {
listenerEvent(serviceListener -> serviceListener.onUnsubscribe(url, registry));
}
}

@Override
public boolean isServiceDiscovery() {
return registry.isServiceDiscovery();
return registry != null && registry.isServiceDiscovery();
}

@Override
public List<URL> lookup(URL url) {
return registry.lookup(url);
return registry == null ? Collections.emptyList() : registry.lookup(url);
}

public Registry getRegistry() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,13 @@ public void subscribe(URL url) {
consumerConfigurationListener.addNotifyListener(this);
referenceConfigurationListener = new ReferenceConfigurationListener(moduleModel, this, url);
}
String registryClusterName = registry.getUrl()
.getParameter(
RegistryConstants.REGISTRY_CLUSTER_KEY,
registry.getUrl().getParameter(PROTOCOL_KEY));
// registry.getUrl() may be null when the registry is unavailable and check=false (e.g. a weakly
// dependent registry is down at startup), in which case there is no cluster name to report.
URL registryUrl = registry.getUrl();
String registryClusterName = registryUrl == null
? null
: registryUrl.getParameter(
RegistryConstants.REGISTRY_CLUSTER_KEY, registryUrl.getParameter(PROTOCOL_KEY));
MetricsEventBus.post(RegistryEvent.toSubscribeEvent(applicationModel, registryClusterName), () -> {
super.subscribe(url);
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.apache.dubbo.common.url.component.ServiceConfigURL;
import org.apache.dubbo.registry.integration.DemoService;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

Expand Down Expand Up @@ -73,4 +74,31 @@ void testSubscribe() {
registryWrapper.subscribe(subscribeUrl, notifyListener);
verify(listener, times(1)).onSubscribe(subscribeUrl, registry);
}

@Test
void testNullRegistryIsTolerated() {
// When a registry is unavailable and check=false (e.g. a weakly dependent registry is down at
// startup), AbstractRegistryFactory returns a null registry which RegistryFactoryWrapper still
// wraps. The wrapper must tolerate the null delegate instead of throwing NullPointerException.
// See https://github.com/apache/dubbo/issues/16178.
ListenerRegistryWrapper wrapper = new ListenerRegistryWrapper(null, Collections.emptyList());

URL url = new ServiceConfigURL("dubbo", "127.0.0.1", 20881, DemoService.class.getName(), new HashMap<>());
NotifyListener notifyListener = mock(NotifyListener.class);

Assertions.assertNull(wrapper.getRegistry());
Assertions.assertNull(wrapper.getUrl());
Assertions.assertFalse(wrapper.isAvailable());
Assertions.assertFalse(wrapper.isServiceDiscovery());
Assertions.assertTrue(wrapper.lookup(url).isEmpty());

// register / subscribe / lifecycle methods must be no-ops rather than throwing
Assertions.assertDoesNotThrow(() -> {
wrapper.register(url);
wrapper.unregister(url);
wrapper.subscribe(url, notifyListener);
wrapper.unsubscribe(url, notifyListener);
wrapper.destroy();
});
}
}
Loading