@Override
    public void doSubscribe(URL url, NotifyListener listener) {
        url = addRegistryClusterKey(url);

        serviceDiscovery.subscribe(url, listener);

        Set<String> mappingByUrl = ServiceNameMapping.getMappingByUrl(url);

        String key = ServiceNameMapping.buildMappingKey(url);

        if (mappingByUrl == null) {
            Lock mappingLock = serviceNameMapping.getMappingLock(key);
            try {
                mappingLock.lock();
                mappingByUrl = serviceNameMapping.getMapping(url);
                try {
                    MappingListener mappingListener = new DefaultMappingListener(url, mappingByUrl, listener);
                    mappingByUrl = serviceNameMapping.getAndListen(this.getUrl(), url, mappingListener);
                    synchronized (mappingListeners) {
                        mappingListeners
                                .computeIfAbsent(url.getProtocolServiceKey(), (k) -> new ConcurrentHashSet<>())
                                .add(mappingListener);
                    }
                } catch (Exception e) {
                    logger.warn(
                            INTERNAL_ERROR,
                            "",
                            "",
                            "Cannot find app mapping for service " + url.getServiceInterface() + ", will not migrate.",
                            e);
                }

                if (CollectionUtils.isEmpty(mappingByUrl)) {
                    logger.info(
                            "No interface-apps mapping found in local cache, stop subscribing, will automatically wait for mapping listener callback: "
                                    + url);
                    //                if (check) {
                    //                    throw new IllegalStateException("Should has at least one way to know which
                    // services this interface belongs to, subscription url: " + url);
                    //                }
                    return;
                }
            } finally {
                mappingLock.unlock();
            }
        }
        subscribeURLs(url, listener, mappingByUrl);
    }
@Test
    void testDoSubscribe() {
        ApplicationModel applicationModel = spy(ApplicationModel.defaultModel());
        when(applicationModel.getDefaultExtension(ServiceNameMapping.class)).thenReturn(mapping);
        // Exceptional case, no interface-app mapping found
        when(mapping.getAndListen(any(), any(), any())).thenReturn(Collections.emptySet());
        // when check = false
        try {
            registryURL = registryURL.setScopeModel(applicationModel);
            serviceDiscoveryRegistry = new ServiceDiscoveryRegistry(registryURL, serviceDiscovery, mapping);
            serviceDiscoveryRegistry.doSubscribe(url, testServiceListener);
        } finally {
            registryURL = registryURL.setScopeModel(null);
            serviceDiscoveryRegistry.unsubscribe(url, testServiceListener);
        }
        //        // when check = true
        URL checkURL = url.addParameter(CHECK_KEY, true);
        checkURL.setScopeModel(url.getApplicationModel());
        //        Exception exceptionShouldHappen = null;
        //        try {
        //            serviceDiscoveryRegistry.doSubscribe(checkURL, testServiceListener);
        //        } catch (IllegalStateException e) {
        //            exceptionShouldHappen = e;
        //        } finally {
        //            serviceDiscoveryRegistry.unsubscribe(checkURL, testServiceListener);
        //        }
        //        if (exceptionShouldHappen == null) {
        //            fail();
        //        }

        // Normal case
        Set<String> singleApp = new HashSet<>();
        singleApp.add(APP_NAME1);
        when(mapping.getAndListen(any(), any(), any())).thenReturn(singleApp);
        try {
            serviceDiscoveryRegistry.doSubscribe(checkURL, testServiceListener);
        } finally {
            serviceDiscoveryRegistry.unsubscribe(checkURL, testServiceListener);
        }

        // test provider case
        checkURL = url.addParameter(PROVIDED_BY, APP_NAME1);

        try {
            serviceDiscoveryRegistry.doSubscribe(checkURL, testServiceListener);
        } finally {
            serviceDiscoveryRegistry.unsubscribe(checkURL, testServiceListener);
        }
    }