You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by li...@apache.org on 2021/12/27 06:23:15 UTC

[dubbo] 01/03: Merge branch '3.0' into 3.0-metadata-refactor

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

liujun pushed a commit to branch 3.0-metadata-refactor
in repository https://gitbox.apache.org/repos/asf/dubbo.git

commit 15ec53ec126e0754fdd805a3a7b96de2990068ce
Merge: f7c5e20 f06bbcc
Author: ken.lj <ke...@gmail.com>
AuthorDate: Mon Dec 27 11:41:25 2021 +0800

    Merge branch '3.0' into 3.0-metadata-refactor
    
    # Conflicts:
    #	dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DefaultFilterChainBuilderTest.java
    #	dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/route/MeshAppRuleListenerTest.java
    #	dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/route/StandardMeshRuleRouterFactoryTest.java
    #	dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/rule/virtualservice/DubboMatchRequestTest.java
    #	dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/mesh/util/VsDestinationGroupRuleDispatcherTest.java
    #	dubbo-common/src/main/java/org/apache/dubbo/common/config/CompositeConfiguration.java
    #	dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
    #	dubbo-dependencies-bom/pom.xml
    #	dubbo-dependencies/dubbo-dependencies-zookeeper/pom.xml
    #	dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/InstanceAddressURL.java
    #	dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java
    #	dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListener.java
    #	dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataUtils.java
    #	dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/AbstractRegistry.java
    #	dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListenerTest.java
    #	dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java
    #	dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/LazyConnectExchangeClient.java
    #	pom.xml

 .github/workflows/build-and-test-3.yml             |   53 +-
 compiler/pom.xml                                   |    2 +-
 .../rpc/cluster/ClusterScopeModelInitializer.java  |    4 +-
 .../org/apache/dubbo/rpc/cluster/Constants.java    |    2 +
 .../org/apache/dubbo/rpc/cluster/RouterChain.java  |   43 +-
 .../cluster/filter/DefaultFilterChainBuilder.java  |   81 +-
 .../rpc/cluster/filter/FilterChainBuilder.java     |  204 ++-
 .../filter/support/ConsumerContextFilter.java      |   46 +-
 .../router/mesh/route/MeshAppRuleListener.java     |  111 +-
 .../route/MeshRuleAddressListenerInterceptor.java  |   60 -
 .../cluster/router/mesh/route/MeshRuleCache.java   |  170 ++
 .../router/mesh/route/MeshRuleConstants.java       |   26 +-
 .../cluster/router/mesh/route/MeshRuleManager.java |   98 +-
 .../cluster/router/mesh/route/MeshRuleRouter.java  |  431 +++---
 ...terFactory.java => StandardMeshRuleRouter.java} |   27 +-
 ...ory.java => StandardMeshRuleRouterFactory.java} |   10 +-
 .../rpc/cluster/router/mesh/rule/BaseRule.java     |   10 +-
 .../router/mesh/rule/VsDestinationGroup.java       |    4 +
 .../rule/virtualservice/DubboMatchRequest.java     |   63 +-
 .../mesh/rule/virtualservice/match/BoolMatch.java  |    6 +-
 .../rule/virtualservice/match/DoubleMatch.java     |   16 +-
 .../virtualservice/match/DoubleRangeMatch.java     |   14 +-
 .../virtualservice/match/DubboAttachmentMatch.java |   61 +-
 .../rule/virtualservice/match/DubboMethodArg.java  |   16 +-
 .../virtualservice/match/DubboMethodMatch.java     |   60 +-
 .../rule/virtualservice/match/ListBoolMatch.java   |    6 +-
 .../rule/virtualservice/match/ListDoubleMatch.java |    6 +-
 .../rule/virtualservice/match/ListStringMatch.java |    6 +-
 .../rule/virtualservice/match/StringMatch.java     |   27 +-
 .../router/mesh/util/MeshRuleDispatcher.java       |  104 ++
 ...roupRuleListener.java => MeshRuleListener.java} |   11 +-
 .../router/mesh/util/TracingContextProvider.java   |   23 +-
 .../util/VsDestinationGroupRuleDispatcher.java     |   53 -
 .../dubbo/rpc/cluster/router/state/BitList.java    |   47 +-
 .../cluster/router/state/StateRouterResult.java    |   30 +
 .../cluster/support/FailoverClusterInvoker.java    |    6 +-
 .../org.apache.dubbo.registry.AddressListener      |    1 -
 .../org.apache.dubbo.rpc.cluster.RouterFactory     |    1 -
 ...bbo.rpc.cluster.router.state.StateRouterFactory |    1 +
 .../apache/dubbo/rpc/cluster/RouterChainTest.java  |    4 +-
 .../filter/DefaultFilterChainBuilderTest.java      |   12 +-
 .../router/mesh/route/MeshAppRuleListenerTest.java |  423 +++--
 .../router/mesh/route/MeshRuleCacheTest.java       |  110 ++
 .../router/mesh/route/MeshRuleManagerTest.java     |  350 +++--
 .../router/mesh/route/MeshRuleRouterTest.java      | 1637 ++++----------------
 ...java => StandardMeshRuleRouterFactoryTest.java} |   12 +-
 .../router/mesh/rule/DestinationRuleTest.java      |    6 +-
 .../rule/virtualservice/DubboMatchRequestTest.java |  139 +-
 .../rule/virtualservice/match/BoolMatchTest.java   |    8 +-
 .../rule/virtualservice/match/DoubleMatchTest.java |   30 +-
 .../match/DubboAttachmentMatchTest.java            |  138 +-
 .../virtualservice/match/DubboMethodMatchTest.java |   27 +-
 .../virtualservice/match/ListBoolMatchTest.java    |    6 +-
 .../virtualservice/match/ListDoubleMatchTest.java  |    6 +-
 .../virtualservice/match/ListStringMatchTest.java  |    6 +-
 .../rule/virtualservice/match/StringMatchTest.java |   32 +-
 .../router/mesh/util/MeshRuleDispatcherTest.java   |  213 +++
 .../util/VsDestinationGroupRuleDispatcherTest.java |   75 -
 .../router/mock/MockInvokersSelectorTest.java      |    4 +-
 .../support/FailoverClusterInvokerTest.java        |    2 +-
 .../support/MergeableClusterInvokerTest.java       |    5 +-
 .../support/wrapper/AbstractClusterTest.java       |    6 +-
 .../java/org/apache/dubbo/common/Experimental.java |    2 +-
 .../java/org/apache/dubbo/common/URLBuilder.java   |    6 +
 .../org/apache/dubbo/common/bytecode/Wrapper.java  |   14 +-
 .../common/config/CompositeConfiguration.java      |   15 +-
 .../dubbo/common/config/ConfigurationCache.java    |    3 +-
 .../dubbo/common/config/ConfigurationUtils.java    |   15 +-
 .../dubbo/common/config/InmemoryConfiguration.java |    6 +-
 .../configcenter/TreePathDynamicConfiguration.java |    2 +-
 .../dubbo/common/constants/CommonConstants.java    |   17 +
 .../dubbo/common/constants/RegistryConstants.java  |    6 +-
 .../dubbo/common/deploy/ApplicationDeployer.java   |    4 +-
 .../org/apache/dubbo/common/deploy/Deployer.java   |    2 -
 .../dubbo/common/extension/ExtensionDirector.java  |    8 +-
 .../dubbo/common/extension/ExtensionLoader.java    |    6 +-
 .../org/apache/dubbo/common/extension/Wrapper.java |    8 +
 .../extension/support/ActivateComparator.java      |    6 +-
 ...r.java => MultiInstanceActivateComparator.java} |   41 +-
 .../extension/support/WrapperComparator.java       |    6 +
 .../dubbo/common/json/GenericJSONConverter.java    |  528 -------
 .../org/apache/dubbo/common/json/J2oVisitor.java   |  389 -----
 .../java/org/apache/dubbo/common/json/JSON.java    |  711 ---------
 .../org/apache/dubbo/common/json/JSONArray.java    |  184 ---
 .../apache/dubbo/common/json/JSONConverter.java    |   44 -
 .../org/apache/dubbo/common/json/JSONObject.java   |  209 ---
 .../org/apache/dubbo/common/json/JSONReader.java   |   68 -
 .../org/apache/dubbo/common/json/JSONToken.java    |   72 -
 .../org/apache/dubbo/common/json/JSONVisitor.java  |  107 --
 .../org/apache/dubbo/common/json/JSONWriter.java   |  305 ----
 .../java/org/apache/dubbo/common/json/Yylex.java   |  847 ----------
 .../reporter/FrameworkStatusReportService.java     |    5 +-
 .../org/apache/dubbo/common/utils/ClassUtils.java  |   74 +
 .../org/apache/dubbo/config/AbstractConfig.java    |   36 +-
 .../dubbo/config/AbstractInterfaceConfig.java      |    5 +-
 .../apache/dubbo/config/AbstractMethodConfig.java  |    2 +-
 .../dubbo/config/AbstractReferenceConfig.java      |    8 +-
 .../apache/dubbo/config/AbstractServiceConfig.java |    4 +-
 .../org/apache/dubbo/config/ApplicationConfig.java |   35 +-
 .../apache/dubbo/config/MetadataReportConfig.java  |   14 +-
 .../java/org/apache/dubbo/config/MethodConfig.java |    5 +-
 .../java/org/apache/dubbo/config/ModuleConfig.java |    4 +-
 .../org/apache/dubbo/config/MonitorConfig.java     |    2 +-
 .../apache/dubbo/config/ReferenceConfigBase.java   |   12 +-
 .../org/apache/dubbo/config/RegistryConfig.java    |   28 +-
 .../org/apache/dubbo/config/ServiceConfigBase.java |    2 +-
 .../config/context/ConfigConfigurationAdapter.java |    2 +-
 .../dubbo/rpc/model/ModuleServiceRepository.java   |    2 +
 .../org/apache/dubbo/rpc/model/ScopeModelUtil.java |    5 +-
 .../apache/dubbo/common/bytecode/WrapperTest.java  |    5 +
 .../config/EnvironmentConfigurationTest.java       |    2 +-
 .../common/extension/ExtensionLoaderTest.java      |   33 +-
 .../extension/ext6_wrap/impl/Ext6Impl3.java}       |   19 +-
 .../common/extension/ext6_wrap/impl/Ext6Impl4.java |   17 +-
 .../extension/ext6_wrap/impl/Ext6Wrapper1.java     |    2 +
 .../extension/ext6_wrap/impl/Ext6Wrapper2.java     |    2 +
 .../impl/{Ext6Wrapper1.java => Ext6Wrapper3.java}  |    7 +-
 .../impl/{Ext6Wrapper1.java => Ext6Wrapper4.java}  |    7 +-
 .../apache/dubbo/common/json/JSONReaderTest.java   |   44 -
 .../org/apache/dubbo/common/json/JSONTest.java     |  227 ---
 .../apache/dubbo/common/json/JSONWriterTest.java   |   50 -
 .../apache/dubbo/rpc/model/FrameworkModelTest.java |    1 +
 ...che.dubbo.common.extension.ext6_wrap.WrappedExt |    4 +
 .../org/apache/dubbo/config/ReferenceConfig.java   |   18 +-
 .../org/apache/dubbo/config/ServiceConfig.java     |   24 +-
 .../dubbo/config/bootstrap/DubboBootstrap.java     |   30 +
 .../config/deploy/DefaultApplicationDeployer.java  |   12 +-
 .../dubbo/config/deploy/DefaultModuleDeployer.java |    3 +-
 .../ConfigurableMetadataServiceExporter.java       |    3 +-
 .../dubbo/config/utils/ConfigValidationUtils.java  |    8 +-
 .../apache/dubbo/config/AbstractConfigTest.java    |   11 +-
 .../dubbo/config/AbstractReferenceConfigTest.java  |    4 +-
 .../apache/dubbo/config/ApplicationConfigTest.java |  150 +-
 .../dubbo/config/ConfigCenterConfigTest.java       |  136 +-
 .../apache/dubbo/config/ConsumerConfigTest.java    |  157 +-
 .../org/apache/dubbo/config/MethodConfigTest.java  |    2 +
 .../apache/dubbo/config/ProtocolConfigTest.java    |    2 -
 .../apache/dubbo/config/ProviderConfigTest.java    |    2 +-
 .../apache/dubbo/config/ReferenceConfigTest.java   |   19 +-
 .../org/apache/dubbo/config/ServiceConfigTest.java |    9 +-
 .../AbstractRegistryCenterExporterListener.java    |   34 +-
 dubbo-config/dubbo-config-spring/pom.xml           |    5 +
 .../src/main/resources/META-INF/compat/dubbo.xsd   |   22 +-
 .../src/main/resources/META-INF/dubbo.xsd          |   18 +-
 .../support/zookeeper/CacheListener.java           |    4 -
 .../zookeeper/ZookeeperDynamicConfiguration.java   |    7 +-
 .../dubbo-demo-spring-boot-consumer/pom.xml        |    7 +
 .../dubbo-demo-spring-boot-provider/pom.xml        |    7 +
 dubbo-dependencies-bom/pom.xml                     |    3 +-
 .../metadata/report/MetadataReportFactory.java     |    9 +-
 .../report/support/AbstractMetadataReport.java     |    8 +-
 .../dubbo/metadata/report/support/Constants.java   |    8 -
 .../store/redis/RedisMetadataReportTest.java       |    2 +-
 .../META-INF/native-image/reflect-config.json      |    2 +-
 .../dubbo/auth/filter/ProviderAuthFilterTest.java  |   15 +-
 .../org/apache/dubbo/registry/RegistryFactory.java |    3 +-
 .../dubbo/registry/client/InstanceAddressURL.java  |   15 +-
 .../client/ServiceDiscoveryRegistryDirectory.java  |    7 +-
 .../listener/ServiceInstancesChangedListener.java  |   14 +-
 .../metadata/ServiceInstanceMetadataUtils.java     |    5 +-
 .../client/migration/MigrationInvoker.java         |   19 +-
 .../registry/integration/DynamicDirectory.java     |   18 +-
 .../registry/integration/RegistryDirectory.java    |    1 +
 .../registry/integration/RegistryProtocol.java     |    2 +-
 .../dubbo/registry/support/AbstractRegistry.java   |    2 +-
 .../registry/support/AbstractRegistryFactory.java  |    4 +-
 .../support/CacheableFailbackRegistry.java         |   10 +-
 .../registry/CacheableFailbackRegistryTest.java    |   59 +
 .../dubbo/registry/MockCacheableRegistryImpl.java  |   12 +
 .../ServiceInstancesChangedListenerTest.java       |   37 +-
 .../client/migration/MigrationInvokerTest.java     |    3 +
 .../dubbo/registry/multiple/MultipleRegistry.java  |    2 +-
 .../multiple/MultipleRegistry2S2RTest.java         |    2 +-
 .../apache/dubbo/registry/nacos/NacosRegistry.java |    5 +-
 .../zookeeper/util/CuratorFrameworkUtils.java      |    2 +-
 .../java/org/apache/dubbo/remoting/Constants.java  |    2 +-
 .../telnet/support/TelnetHandlerAdapter.java       |    4 +-
 .../support/command/StatusTelnetHandler.java       |    3 +-
 .../dubbo/remoting/transport/AbstractEndpoint.java |   11 +-
 .../transport/netty/NettyBackedChannelBuffer.java  |    7 +-
 .../support/header/HeartbeatHandlerTest.java       |   19 +-
 .../transport/netty/ClientReconnectTest.java       |    2 +-
 .../netty/NettyBackedChannelBufferTest.java        |   63 +
 .../remoting/transport/netty/NettyClientTest.java  |    8 +-
 .../transport/netty/NettyClientToServerTest.java   |    4 +-
 .../remoting/transport/netty/NettyStringTest.java  |    4 +-
 .../remoting/transport/netty/ThreadNameTest.java   |    4 +-
 .../transport/netty4/NettyBackedChannelBuffer.java |    8 +-
 .../netty4/NettyBackedChannelBufferTest.java       |   65 +
 .../java/org/apache/dubbo/rpc/AsyncContext.java    |   46 +
 .../org/apache/dubbo/rpc/AsyncContextImpl.java     |   25 +-
 .../java/org/apache/dubbo/rpc/AsyncRpcResult.java  |   45 +-
 .../main/java/org/apache/dubbo/rpc/BaseFilter.java |   23 +
 .../org/apache/dubbo/rpc/ListenableFilter.java     |    3 +-
 .../main/java/org/apache/dubbo/rpc/RpcContext.java |   64 +-
 .../org/apache/dubbo/rpc/RpcContextAttachment.java |   24 +
 .../org/apache/dubbo/rpc/RpcServiceContext.java    |   28 +-
 ...rFilter.java => ClassLoaderCallbackFilter.java} |   33 +-
 .../apache/dubbo/rpc/filter/ClassLoaderFilter.java |   40 +-
 .../org/apache/dubbo/rpc/filter/ContextFilter.java |   24 +-
 .../dubbo/rpc/proxy/AbstractProxyInvoker.java      |   14 +-
 .../rpc/proxy/javassist/JavassistProxyFactory.java |   60 +-
 .../dubbo/internal/org.apache.dubbo.rpc.Filter     |    3 +-
 .../java/org/apache/dubbo/rpc/RpcContextTest.java  |    5 +
 .../dubbo/rpc/filter/ClassLoaderFilterTest.java    |    4 +
 .../rpc/filter/CompatibleFilterFilterTest.java     |   19 +-
 .../apache/dubbo/rpc/filter/ContextFilterTest.java |    6 +-
 .../apache/dubbo/rpc/filter/EchoFilterTest.java    |    3 +-
 .../apache/dubbo/rpc/filter/TimeoutFilterTest.java |    3 +-
 .../apache/dubbo/rpc/support/MockInvocation.java   |    4 +-
 .../rpc/protocol/dubbo/CallbackServiceCodec.java   |    4 +-
 .../dubbo/rpc/protocol/dubbo/DubboProtocol.java    |    7 +-
 .../protocol/dubbo/LazyConnectExchangeClient.java  |    2 +-
 .../dubbo/ReferenceCountExchangeClient.java        |   21 +-
 .../rpc/protocol/dubbo/DubboProtocolTest.java      |   31 +-
 .../dubbo/rpc/protocol/dubbo/RpcFilterTest.java    |    1 +
 .../rpc/protocol/tri/AbstractClientStream.java     |    4 +-
 .../rpc/protocol/tri/AbstractServerStream.java     |    2 +-
 .../dubbo/rpc/protocol/tri/AbstractStream.java     |    6 +-
 .../apache/dubbo/rpc/protocol/tri/Compressor.java  |    5 +-
 .../apache/dubbo/rpc/protocol/tri/GrpcStatus.java  |   17 +-
 .../dubbo/rpc/protocol/tri/IdentityCompressor.java |    3 +-
 .../rpc/protocol/tri/InboundTransportObserver.java |    2 +-
 .../dubbo/rpc/protocol/tri/UnaryClientStream.java  |    2 +-
 .../rpc/protocol/tri/command/DataQueueCommand.java |    2 +-
 .../org.apache.dubbo.rpc.protocol.tri.Compressor   |    1 -
 .../dubbo/rpc/protocol/tri/ClientStreamTest.java   |    4 +-
 .../dubbo/rpc/protocol/tri/CompressorTest.java     |    2 +-
 .../dubbo/rpc/protocol/tri/GrpcStatusTest.java     |    2 +-
 .../dubbo-spring-boot-actuator/README.md           |    2 +-
 .../dubbo-spring-boot-actuator/pom.xml             |   20 +
 .../DubboEndpointAnnotationAutoConfiguration.java  |    7 +
 .../CompatibleOnEnabledEndpointCondition.java      |   51 +-
 .../dubbo-spring-boot-autoconfigure/pom.xml        |   14 +
 .../dubbo-spring-boot-compatible/actuator/pom.xml  |    7 +
 .../autoconfigure/pom.xml                          |   14 +
 .../dubbo-spring-boot-starter/pom.xml              |   13 +
 dubbo-spring-boot/pom.xml                          |    2 +
 pom.xml                                            |    2 +-
 239 files changed, 4302 insertions(+), 7078 deletions(-)

diff --cc dubbo-common/src/main/java/org/apache/dubbo/common/config/CompositeConfiguration.java
index 154a993,a1e5e0e..34e7754
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/CompositeConfiguration.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/CompositeConfiguration.java
@@@ -47,11 -47,7 +47,7 @@@ public class CompositeConfiguration imp
          }
      }
  
-     public void setDynamicIncluded(boolean dynamicIncluded) {
-         this.dynamicIncluded = dynamicIncluded;
-     }
- 
 -    //FIXME, consider change configList to SortedMap to replace this boolean status.
 +    //FIXME, consider changing configList to SortedMap to replace this boolean status.
      public boolean isDynamicIncluded() {
          return dynamicIncluded;
      }
diff --cc dubbo-common/src/main/java/org/apache/dubbo/common/deploy/ApplicationDeployer.java
index 0b74696,e882434..611f47c
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/ApplicationDeployer.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/deploy/ApplicationDeployer.java
@@@ -82,8 -77,10 +82,10 @@@ public interface ApplicationDeployer ex
      /**
       * check all module state and update application state
       */
 -    void checkState();
 +    void checkState(ModuleModel moduleModel, DeployState moduleState);
  
-     // module state changed callbacks
+     /**
+      * module state changed callbacks
+      */
      void notifyModuleChanged(ModuleModel moduleModel, DeployState state);
  }
diff --cc dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
index 1b62f06,5d83fed..03875d9
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
@@@ -254,9 -254,8 +254,9 @@@ public class ReferenceConfig<T> extend
              this.refresh();
          }
  
-         //init serviceMetadata
+         // init serviceMetadata
          initServiceMetadata(consumer);
 +
          serviceMetadata.setServiceType(getServiceInterfaceClass());
          // TODO, uncomment this line once service key is unified
          serviceMetadata.setServiceKey(URL.buildKey(interfaceName, group, version));
diff --cc dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
index 880fce3,bf7ae84..4d1420f
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
@@@ -540,10 -541,9 +540,9 @@@ public class ServiceConfig<T> extends S
          }
  
          // export service
 -        String host = findConfiguredHosts(protocolConfig, params);
 -        Integer port = findConfiguredPorts(protocolConfig, name, params);
 +        String host = findConfiguredHosts(protocolConfig, provider, registryURLs, params);
 +        Integer port = findConfiguredPort(protocolConfig, provider, this.getExtensionLoader(Protocol.class), name, params);
          URL url = new ServiceConfigURL(name, null, null, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), params);
-         url.setScopeModel(getScopeModel());
  
          // You can customize Configurator to append extra parameters
          if (this.getExtensionLoader(ConfiguratorFactory.class)
@@@ -790,9 -765,9 +788,9 @@@
          return portToRegistry;
      }
  
 -    private Integer parsePort(String configPort) {
 +    private static Integer parsePort(String configPort) {
          Integer port = null;
-         if (configPort != null && configPort.length() > 0) {
+         if (StringUtils.isNotEmpty(configPort)) {
              try {
                  int intPort = Integer.parseInt(configPort);
                  if (isInvalidPort(intPort)) {
diff --cc dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReport.java
index 36b99d0,093fadb..71901c5
--- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReport.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/support/AbstractMetadataReport.java
@@@ -71,11 -73,11 +74,8 @@@ import static org.apache.dubbo.metadata
  import static org.apache.dubbo.metadata.report.support.Constants.DEFAULT_METADATA_REPORT_RETRY_PERIOD;
  import static org.apache.dubbo.metadata.report.support.Constants.DEFAULT_METADATA_REPORT_RETRY_TIMES;
  import static org.apache.dubbo.metadata.report.support.Constants.DUBBO_METADATA;
- import static org.apache.dubbo.metadata.report.support.Constants.RETRY_PERIOD_KEY;
- import static org.apache.dubbo.metadata.report.support.Constants.RETRY_TIMES_KEY;
- import static org.apache.dubbo.metadata.report.support.Constants.SYNC_REPORT_KEY;
  import static org.apache.dubbo.metadata.report.support.Constants.USER_HOME;
  
 -/**
 - *
 - */
  public abstract class AbstractMetadataReport implements MetadataReport {
  
      protected final static String DEFAULT_ROOT = "dubbo";
diff --cc dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/AbstractRegistry.java
index 7391fc3,cc9e6f5..a9a006e
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/AbstractRegistry.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/AbstractRegistry.java
@@@ -95,8 -94,7 +95,8 @@@ public abstract class AbstractRegistry 
      // Local disk cache file
      private File file;
      private boolean localCacheEnabled;
-     private RegistryManager registryManager;
+     protected RegistryManager registryManager;
 +    protected ApplicationModel applicationModel;
  
      public AbstractRegistry(URL url) {
          setUrl(url);
diff --cc dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListenerTest.java
index cc0602e,867face..7bc53c9
--- a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListenerTest.java
+++ b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListenerTest.java
@@@ -14,407 -14,431 +14,422 @@@
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
 -package org.apache.dubbo.registry.client.event.listener;
 -
 -import org.apache.dubbo.common.URL;
 -import org.apache.dubbo.common.utils.StringUtils;
 -import org.apache.dubbo.metadata.MetadataInfo;
 -import org.apache.dubbo.metadata.MetadataService;
 -import org.apache.dubbo.registry.NotifyListener;
 -import org.apache.dubbo.registry.client.DefaultServiceInstance;
 -import org.apache.dubbo.registry.client.InstanceAddressURL;
 -import org.apache.dubbo.registry.client.ServiceDiscovery;
 -import org.apache.dubbo.registry.client.ServiceInstance;
 -import org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;
 -import org.apache.dubbo.registry.client.metadata.MetadataUtils;
 -
 -import com.google.gson.Gson;
 -import org.apache.dubbo.rpc.model.ApplicationModel;
 -import org.hamcrest.Matchers;
 -import org.junit.jupiter.api.AfterEach;
 -import org.junit.jupiter.api.Assertions;
 -import org.junit.jupiter.api.BeforeAll;
 -import org.junit.jupiter.api.MethodOrderer;
 -import org.junit.jupiter.api.Order;
 -import org.junit.jupiter.api.Test;
 -import org.junit.jupiter.api.TestMethodOrder;
 -import org.mockito.ArgumentCaptor;
 -import org.mockito.MockedStatic;
 -import org.mockito.Mockito;
 -import org.mockito.invocation.InvocationOnMock;
 -import org.mockito.stubbing.Answer;
 -
 -import java.util.ArrayList;
 -import java.util.Collections;
 -import java.util.HashMap;
 -import java.util.HashSet;
 -import java.util.List;
 -import java.util.Map;
 -import java.util.Set;
 -import java.util.concurrent.ConcurrentMap;
 -import java.util.concurrent.ThreadLocalRandom;
 -
 -import static org.apache.dubbo.common.constants.CommonConstants.REVISION_KEY;
 -import static org.apache.dubbo.common.utils.CollectionUtils.isEmpty;
 -import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.EXPORTED_SERVICES_REVISION_PROPERTY_NAME;
 -import static org.hamcrest.MatcherAssert.assertThat;
 -import static org.junit.jupiter.api.Assertions.assertTrue;
 -import static org.mockito.ArgumentMatchers.eq;
 -
 -/**
 - * {@link ServiceInstancesChangedListener} Test
 - *
 - * @since 2.7.5
 - */
 -@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
 -public class ServiceInstancesChangedListenerTest {
 -    private static Gson gson = new Gson();
 -
 -    static List<ServiceInstance> app1Instances;
 -    static List<ServiceInstance> app2Instances;
 -    static List<ServiceInstance> app1FailedInstances;
 -    static List<ServiceInstance> app1FailedInstances2;
 -    static List<ServiceInstance> app1InstancesWithNoRevision;
 -
 -    static String metadata_111 = "{\"app\":\"app1\",\"revision\":\"111\",\"services\":{"
 -        + "\"org.apache.dubbo.demo.DemoService:dubbo\":{\"name\":\"org.apache.dubbo.demo.DemoService\",\"protocol\":\"dubbo\",\"path\":\"org.apache.dubbo.demo.DemoService\",\"params\":{\"side\":\"provider\",\"release\":\"\",\"methods\":\"sayHello,sayHelloAsync\",\"deprecated\":\"false\",\"dubbo\":\"2.0.2\",\"pid\":\"72723\",\"interface\":\"org.apache.dubbo.demo.DemoService\",\"service-name-mapping\":\"true\",\"timeout\":\"3000\",\"generic\":\"false\",\"metadata-type\":\"remote\",\"delay [...]
 -        + "}}";
 -    static String metadata_222 = "{\"app\":\"app2\",\"revision\":\"333\",\"services\":{"
 -        + "\"org.apache.dubbo.demo.DemoService:dubbo\":{\"name\":\"org.apache.dubbo.demo.DemoService\",\"protocol\":\"dubbo\",\"path\":\"org.apache.dubbo.demo.DemoService\",\"params\":{\"side\":\"provider\",\"release\":\"\",\"methods\":\"sayHello,sayHelloAsync\",\"deprecated\":\"false\",\"dubbo\":\"2.0.2\",\"pid\":\"72723\",\"interface\":\"org.apache.dubbo.demo.DemoService\",\"service-name-mapping\":\"true\",\"timeout\":\"3000\",\"generic\":\"false\",\"metadata-type\":\"remote\",\"delay [...]
 -        + "\"org.apache.dubbo.demo.DemoService2:dubbo\":{\"name\":\"org.apache.dubbo.demo.DemoService2\",\"protocol\":\"dubbo\",\"path\":\"org.apache.dubbo.demo.DemoService2\",\"params\":{\"side\":\"provider\",\"release\":\"\",\"methods\":\"sayHello,sayHelloAsync\",\"deprecated\":\"false\",\"dubbo\":\"2.0.2\",\"pid\":\"72723\",\"interface\":\"org.apache.dubbo.demo.DemoService2\",\"service-name-mapping\":\"true\",\"timeout\":\"3000\",\"generic\":\"false\",\"metadata-type\":\"remote\",\"d [...]
 -        + "}}";
 -    static String metadata_333 = "{\"app\":\"app2\",\"revision\":\"333\",\"services\":{"
 -        + "\"org.apache.dubbo.demo.DemoService:dubbo\":{\"name\":\"org.apache.dubbo.demo.DemoService\",\"protocol\":\"dubbo\",\"path\":\"org.apache.dubbo.demo.DemoService\",\"params\":{\"side\":\"provider\",\"release\":\"\",\"methods\":\"sayHello,sayHelloAsync\",\"deprecated\":\"false\",\"dubbo\":\"2.0.2\",\"pid\":\"72723\",\"interface\":\"org.apache.dubbo.demo.DemoService\",\"service-name-mapping\":\"true\",\"timeout\":\"3000\",\"generic\":\"false\",\"metadata-type\":\"remote\",\"delay [...]
 -        + "\"org.apache.dubbo.demo.DemoService2:dubbo\":{\"name\":\"org.apache.dubbo.demo.DemoService2\",\"protocol\":\"dubbo\",\"path\":\"org.apache.dubbo.demo.DemoService2\",\"params\":{\"side\":\"provider\",\"release\":\"\",\"methods\":\"sayHello,sayHelloAsync\",\"deprecated\":\"false\",\"dubbo\":\"2.0.2\",\"pid\":\"72723\",\"interface\":\"org.apache.dubbo.demo.DemoService2\",\"service-name-mapping\":\"true\",\"timeout\":\"3000\",\"generic\":\"false\",\"metadata-type\":\"remote\",\"d [...]
 -        + "\"org.apache.dubbo.demo.DemoService3:dubbo\":{\"name\":\"org.apache.dubbo.demo.DemoService3\",\"protocol\":\"dubbo\",\"path\":\"org.apache.dubbo.demo.DemoService3\",\"params\":{\"side\":\"provider\",\"release\":\"\",\"methods\":\"sayHello,sayHelloAsync\",\"deprecated\":\"false\",\"dubbo\":\"2.0.2\",\"pid\":\"72723\",\"interface\":\"org.apache.dubbo.demo.DemoService3\",\"service-name-mapping\":\"true\",\"timeout\":\"3000\",\"generic\":\"false\",\"metadata-type\":\"remote\",\"d [...]
 -        + "}}";
 -    // failed
 -    static String metadata_444 = "{\"app\":\"app1\",\"revision\":\"444\",\"services\":{"
 -        + "\"org.apache.dubbo.demo.DemoService:dubbo\":{\"name\":\"org.apache.dubbo.demo.DemoService\",\"protocol\":\"dubbo\",\"path\":\"org.apache.dubbo.demo.DemoService\",\"params\":{\"side\":\"provider\",\"release\":\"\",\"methods\":\"sayHello,sayHelloAsync\",\"deprecated\":\"false\",\"dubbo\":\"2.0.2\",\"pid\":\"72723\",\"interface\":\"org.apache.dubbo.demo.DemoService\",\"service-name-mapping\":\"true\",\"timeout\":\"3000\",\"generic\":\"false\",\"metadata-type\":\"remote\",\"delay [...]
 -        + "}}";
 -
 -    static String bad_metadatainfo = "{\"xxx\":\"yyy\"}";
 -
 -    static String service1 = "org.apache.dubbo.demo.DemoService";
 -    static String service2 = "org.apache.dubbo.demo.DemoService2";
 -    static String service3 = "org.apache.dubbo.demo.DemoService3";
 -
 -    static URL consumerURL = URL.valueOf("dubbo://127.0.0.1/org.apache.dubbo.demo.DemoService?registry_cluster=default");
 -    static URL registryURL = URL.valueOf("dubbo://127.0.0.1:2181/org.apache.dubbo.demo.RegistryService");
 -
 -    static MetadataInfo metadataInfo_111;
 -    static MetadataInfo metadataInfo_222;
 -    static MetadataInfo metadataInfo_333;
 -    static MetadataInfo metadataInfo_444;
 -
 -    static MetadataService metadataService;
 -
 -    static ServiceDiscovery serviceDiscovery;
 -
 -    ServiceInstancesChangedListener listener = null;
 -
 -    @BeforeAll
 -    public static void setUp() {
 -        List<Object> urlsSameRevision = new ArrayList<>();
 -        urlsSameRevision.add("127.0.0.1:20880?revision=111");
 -        urlsSameRevision.add("127.0.0.2:20880?revision=111");
 -        urlsSameRevision.add("127.0.0.3:20880?revision=111");
 -
 -        List<Object> urlsDifferentRevision = new ArrayList<>();
 -        urlsDifferentRevision.add("30.10.0.1:20880?revision=222");
 -        urlsDifferentRevision.add("30.10.0.2:20880?revision=222");
 -        urlsDifferentRevision.add("30.10.0.3:20880?revision=333");
 -        urlsDifferentRevision.add("30.10.0.4:20880?revision=333");
 -
 -        List<Object> urlsFailedRevision = new ArrayList<>();
 -        urlsFailedRevision.add("30.10.0.5:20880?revision=222");
 -        urlsFailedRevision.add("30.10.0.6:20880?revision=222");
 -        urlsFailedRevision.add("30.10.0.7:20880?revision=444");// revision will fail
 -        urlsFailedRevision.add("30.10.0.8:20880?revision=444");// revision will fail
 -
 -        List<Object> urlsFailedRevision2 = new ArrayList<>();
 -        urlsFailedRevision2.add("30.10.0.1:20880?revision=222");
 -        urlsFailedRevision2.add("30.10.0.2:20880?revision=222");
 -
 -        List<Object> urlsWithoutRevision = new ArrayList<>();
 -        urlsWithoutRevision.add("30.10.0.1:20880");
 -
 -        app1Instances = buildInstances(urlsSameRevision);
 -        app2Instances = buildInstances(urlsDifferentRevision);
 -        app1FailedInstances = buildInstances(urlsFailedRevision);
 -        app1FailedInstances2 = buildInstances(urlsFailedRevision2);
 -        app1InstancesWithNoRevision = buildInstances(urlsWithoutRevision);
 -
 -        metadataInfo_111 = gson.fromJson(metadata_111, MetadataInfo.class);
 -        metadataInfo_222 = gson.fromJson(metadata_222, MetadataInfo.class);
 -        metadataInfo_333 = gson.fromJson(metadata_333, MetadataInfo.class);
 -        metadataInfo_444 = gson.fromJson(metadata_444, MetadataInfo.class);
 -
 -        metadataService = Mockito.mock(MetadataService.class);
 -        Mockito.doReturn(metadataInfo_111).when(metadataService).getMetadataInfo("111");
 -        Mockito.doReturn(metadataInfo_222).when(metadataService).getMetadataInfo("222");
 -        Mockito.doReturn(metadataInfo_333).when(metadataService).getMetadataInfo("333");
 -        Mockito.doThrow(IllegalStateException.class).when(metadataService).getMetadataInfo("444");
 -
 -        serviceDiscovery = Mockito.mock(ServiceDiscovery.class);
 -        Mockito.doReturn(registryURL).when(serviceDiscovery).getUrl();
 -    }
 -
 -    @AfterEach
 -    public void tearDown() {
 -        if (listener != null) {
 -            listener.destroy();
 -            listener = null;
 -        }
 -    }
 -
 -    // 正常场景。单应用app1 通知地址基本流程,只做instance-metadata关联,没有metadata内容的解析
 -    @Test
 -    @Order(1)
 -    public void testInstanceNotification() {
 -        Set<String> serviceNames = new HashSet<>();
 -        serviceNames.add("app1");
 -        ServiceDiscovery serviceDiscovery = Mockito.mock(ServiceDiscovery.class);
 -        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
 -        ServiceInstancesChangedListener spyListener = Mockito.spy(listener);
 -        Mockito.doReturn(metadataInfo_111).when(spyListener).getRemoteMetadata(eq("111"), Mockito.anyMap(), Mockito.any());
 -        ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent("app1", app1Instances);
 -        spyListener.onEvent(event);
 -
 -        Map<String, List<ServiceInstance>> allInstances = spyListener.getAllInstances();
 -        Assertions.assertEquals(1, allInstances.size());
 -        Assertions.assertEquals(3, allInstances.get("app1").size());
 -
 -        Map<String, MetadataInfo> revisionToMetadata = spyListener.getRevisionToMetadata();
 -        Assertions.assertEquals(1, revisionToMetadata.size());
 -        Assertions.assertEquals(metadataInfo_111, revisionToMetadata.get("111"));
 -
 -//        // test app2 notification
 -//        Mockito.doReturn(metadataInfo_222).when(spyListener).getRemoteMetadata(eq("222"), Mockito.anyMap(), Mockito.anyList());
 -//        Mockito.doReturn(metadataInfo_333).when(spyListener).getRemoteMetadata(eq("333"), Mockito.anyMap(), Mockito.anyList());
 -//
 -//        ServiceInstancesChangedEvent event_app2 = new ServiceInstancesChangedEvent("app2", app2Instances);
 -//        spyListener.onEvent(event_app2);
 -
 -    }
 -
 -    // 正常场景。单应用app1,进一步检查 metadata service 是否正确映射
 -    @Test
 -    @Order(2)
 -    public void testInstanceNotificationAndMetadataParse() {
 -        Set<String> serviceNames = new HashSet<>();
 -        serviceNames.add("app1");
 -        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
 -
 -        try (MockedStatic<MetadataUtils> mockedMetadataUtils = Mockito.mockStatic(MetadataUtils.class)) {
 -            mockedMetadataUtils.when(() -> MetadataUtils.getMetadataServiceProxy(Mockito.any())).thenReturn(metadataService);
 -            // notify instance change
 -            ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent("app1", app1Instances);
 -            listener.onEvent(event);
 -
 -            Map<String, List<ServiceInstance>> allInstances = listener.getAllInstances();
 -            Assertions.assertEquals(1, allInstances.size());
 -            Assertions.assertEquals(3, allInstances.get("app1").size());
 -
 -            Map<String, MetadataInfo> revisionToMetadata = listener.getRevisionToMetadata();
 -            Assertions.assertEquals(1, revisionToMetadata.size());
 -            Assertions.assertEquals(metadataInfo_111, revisionToMetadata.get("111"));
 -
 -            List<URL> serviceUrls = listener.getAddresses(service1 + ":dubbo", consumerURL);
 -            Assertions.assertEquals(3, serviceUrls.size());
 -            assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);
 -
 -            assertThat(serviceUrls, Matchers.hasItem(Matchers.hasProperty("instance", Matchers.notNullValue())));
 -            assertThat(serviceUrls, Matchers.hasItem(Matchers.hasProperty("metadataInfo", Matchers.notNullValue())));
 -
 -        }
 -    }
 -
 -    // 正常场景。多应用,app1 app2 分别通知地址
 -    @Test
 -    @Order(3)
 -    public void testMultipleAppNotification() {
 -        Set<String> serviceNames = new HashSet<>();
 -        serviceNames.add("app1");
 -        serviceNames.add("app2");
 -        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
 -
 -        try (MockedStatic<MetadataUtils> mockedMetadataUtils = Mockito.mockStatic(MetadataUtils.class)) {
 -            mockedMetadataUtils.when(() -> MetadataUtils.getMetadataServiceProxy(Mockito.any())).thenReturn(metadataService);
 -            // notify app1 instance change
 -            ServiceInstancesChangedEvent app1_event = new ServiceInstancesChangedEvent("app1", app1Instances);
 -            listener.onEvent(app1_event);
 -
 -            // notify app2 instance change
 -            ServiceInstancesChangedEvent app2_event = new ServiceInstancesChangedEvent("app2", app2Instances);
 -            listener.onEvent(app2_event);
 -
 -            // check
 -            Map<String, List<ServiceInstance>> allInstances = listener.getAllInstances();
 -            Assertions.assertEquals(2, allInstances.size());
 -            Assertions.assertEquals(3, allInstances.get("app1").size());
 -            Assertions.assertEquals(4, allInstances.get("app2").size());
 -
 -            Map<String, MetadataInfo> revisionToMetadata = listener.getRevisionToMetadata();
 -            Assertions.assertEquals(3, revisionToMetadata.size());
 -            Assertions.assertEquals(metadataInfo_111, revisionToMetadata.get("111"));
 -            Assertions.assertEquals(metadataInfo_222, revisionToMetadata.get("222"));
 -            Assertions.assertEquals(metadataInfo_333, revisionToMetadata.get("333"));
 -
 -            List<URL> serviceUrls = listener.getAddresses(service1 + ":dubbo", consumerURL);
 -            Assertions.assertEquals(7, serviceUrls.size());
 -            List<URL> serviceUrls2 = listener.getAddresses(service2 + ":dubbo", consumerURL);
 -            Assertions.assertEquals(4, serviceUrls2.size());
 -            assertTrue(serviceUrls2.get(0).getIp().contains("30.10."));
 -            List<URL> serviceUrls3 = listener.getAddresses(service3 + ":dubbo", consumerURL);
 -            Assertions.assertEquals(2, serviceUrls3.size());
 -            assertTrue(serviceUrls3.get(0).getIp().contains("30.10."));
 -        }
 -    }
 -
 -    // 正常场景。多应用,app1 app2,空地址通知(边界条件)能否解析出正确的空地址列表
 -    @Test
 -    @Order(4)
 -    public void testMultipleAppEmptyNotification() {
 -        Set<String> serviceNames = new HashSet<>();
 -        serviceNames.add("app1");
 -        serviceNames.add("app2");
 -        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
 -
 -        try (MockedStatic<MetadataUtils> mockedMetadataUtils = Mockito.mockStatic(MetadataUtils.class)) {
 -            mockedMetadataUtils.when(() -> MetadataUtils.getMetadataServiceProxy(Mockito.any())).thenReturn(metadataService);
 -            // notify app1 instance change
 -            ServiceInstancesChangedEvent app1_event = new ServiceInstancesChangedEvent("app1", app1Instances);
 -            listener.onEvent(app1_event);
 -
 -            // notify app2 instance change
 -            ServiceInstancesChangedEvent app2_event = new ServiceInstancesChangedEvent("app2", app2Instances);
 -            listener.onEvent(app2_event);
 -
 -            // empty notification
 -            ServiceInstancesChangedEvent app1_event_again = new ServiceInstancesChangedEvent("app1", Collections.EMPTY_LIST);
 -            listener.onEvent(app1_event_again);
 -
 -            // check app1 cleared
 -            Map<String, List<ServiceInstance>> allInstances = listener.getAllInstances();
 -            Assertions.assertEquals(2, allInstances.size());
 -            Assertions.assertEquals(0, allInstances.get("app1").size());
 -            Assertions.assertEquals(4, allInstances.get("app2").size());
 -
 -            Map<String, MetadataInfo> revisionToMetadata = listener.getRevisionToMetadata();
 -            Assertions.assertEquals(2, revisionToMetadata.size());
 -            Assertions.assertNull(revisionToMetadata.get("111"));
 -            Assertions.assertEquals(metadataInfo_222, revisionToMetadata.get("222"));
 -            Assertions.assertEquals(metadataInfo_333, revisionToMetadata.get("333"));
 -
 -            List<URL> serviceUrls = listener.getAddresses(service1 + ":dubbo", consumerURL);
 -            Assertions.assertEquals(4, serviceUrls.size());
 -            assertTrue(serviceUrls.get(0).getIp().contains("30.10."));
 -            List<URL> serviceUrls2 = listener.getAddresses(service2 + ":dubbo", consumerURL);
 -            Assertions.assertEquals(4, serviceUrls2.size());
 -            assertTrue(serviceUrls2.get(0).getIp().contains("30.10."));
 -            List<URL> serviceUrls3 = listener.getAddresses(service3 + ":dubbo", consumerURL);
 -            Assertions.assertEquals(2, serviceUrls3.size());
 -            assertTrue(serviceUrls3.get(0).getIp().contains("30.10."));
 -
 -            // app2 empty notification
 -            ServiceInstancesChangedEvent app2_event_again = new ServiceInstancesChangedEvent("app2", Collections.EMPTY_LIST);
 -            listener.onEvent(app2_event_again);
 -
 -            // check app2 cleared
 -            Map<String, List<ServiceInstance>> allInstances_app2 = listener.getAllInstances();
 -            Assertions.assertEquals(2, allInstances_app2.size());
 -            Assertions.assertEquals(0, allInstances_app2.get("app1").size());
 -            Assertions.assertEquals(0, allInstances_app2.get("app2").size());
 -
 -            Map<String, MetadataInfo> revisionToMetadata_app2 = listener.getRevisionToMetadata();
 -            Assertions.assertEquals(0, revisionToMetadata_app2.size());
 -
 -            assertTrue(isEmpty(listener.getAddresses(service1 + ":dubbo", consumerURL)));
 -            assertTrue(isEmpty(listener.getAddresses(service2 + ":dubbo", consumerURL)));
 -            assertTrue(isEmpty(listener.getAddresses(service3 + ":dubbo", consumerURL)));
 -        }
 -    }
 -
 -    // 正常场景。检查instance listener -> service listener(Directory)地址推送流程
 -    @Test
 -    @Order(5)
 -    public void testServiceListenerNotification() {
 -        Set<String> serviceNames = new HashSet<>();
 -        serviceNames.add("app1");
 -        serviceNames.add("app2");
 -        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
 -        NotifyListener demoServiceListener = Mockito.mock(NotifyListener.class);
 -        NotifyListener demoService2Listener = Mockito.mock(NotifyListener.class);
 -        listener.addListenerAndNotify(service1 + ":dubbo", demoServiceListener);
 -        listener.addListenerAndNotify(service2 + ":dubbo", demoService2Listener);
 -
 -        try (MockedStatic<MetadataUtils> mockedMetadataUtils = Mockito.mockStatic(MetadataUtils.class)) {
 -            mockedMetadataUtils.when(() -> MetadataUtils.getMetadataServiceProxy(Mockito.any())).thenReturn(metadataService);
 -            // notify app1 instance change
 -            ServiceInstancesChangedEvent app1_event = new ServiceInstancesChangedEvent("app1", app1Instances);
 -            listener.onEvent(app1_event);
 -
 -            // check
 -            ArgumentCaptor<List<URL>> captor = ArgumentCaptor.forClass(List.class);
 -            Mockito.verify(demoServiceListener, Mockito.times(1)).notify(captor.capture());
 -            List<URL> notifiedUrls = captor.getValue();
 -            Assertions.assertEquals(3, notifiedUrls.size());
 -            ArgumentCaptor<List<URL>> captor2 = ArgumentCaptor.forClass(List.class);
 -            Mockito.verify(demoService2Listener, Mockito.times(1)).notify(captor2.capture());
 -            List<URL> notifiedUrls2 = captor2.getValue();
 -            Assertions.assertEquals(0, notifiedUrls2.size());
 -
 -            // notify app2 instance change
 -            ServiceInstancesChangedEvent app2_event = new ServiceInstancesChangedEvent("app2", app2Instances);
 -            listener.onEvent(app2_event);
 -
 -            // check
 -            ArgumentCaptor<List<URL>> app2_captor = ArgumentCaptor.forClass(List.class);
 -            Mockito.verify(demoServiceListener, Mockito.times(2)).notify(app2_captor.capture());
 -            List<URL> app2_notifiedUrls = app2_captor.getValue();
 -            Assertions.assertEquals(7, app2_notifiedUrls.size());
 -            ArgumentCaptor<List<URL>> app2_captor2 = ArgumentCaptor.forClass(List.class);
 -            Mockito.verify(demoService2Listener, Mockito.times(2)).notify(app2_captor2.capture());
 -            List<URL> app2_notifiedUrls2 = app2_captor2.getValue();
 -            Assertions.assertEquals(4, app2_notifiedUrls2.size());
 -        }
 -
 -        // test service listener still get notified when added after instance notification.
 -        NotifyListener demoService3Listener = Mockito.mock(NotifyListener.class);
 -        listener.addListenerAndNotify(service3 + ":dubbo", demoService3Listener);
 -        Mockito.verify(demoService3Listener, Mockito.times(1)).notify(Mockito.anyList());
 -    }
 -
 -    // revision 异常场景。第一次启动,完全拿不到metadata,只能通知部分地址
 -    @Test
 -    @Order(6)
 -    public void testRevisionFailureOnStartup() {
 -        Set<String> serviceNames = new HashSet<>();
 -        serviceNames.add("app1");
 -        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
 -        try (MockedStatic<MetadataUtils> mockedMetadataUtils = Mockito.mockStatic(MetadataUtils.class)) {
 -            mockedMetadataUtils.when(() -> MetadataUtils.getMetadataServiceProxy(Mockito.any())).thenReturn(metadataService);
 -            // notify app1 instance change
 -            ServiceInstancesChangedEvent failed_revision_event = new ServiceInstancesChangedEvent("app1", app1FailedInstances);
 -            listener.onEvent(failed_revision_event);
 -
 -            List<URL> serviceUrls = listener.getAddresses(service1 + ":dubbo", consumerURL);
 -            List<URL> serviceUrls2 = listener.getAddresses(service2 + ":dubbo", consumerURL);
 -
 -            assertTrue(isEmpty(serviceUrls));
 -            assertTrue(isEmpty(serviceUrls2));
 -
 -            Map<String, MetadataInfo> revisionToMetadata = listener.getRevisionToMetadata();
 -            Assertions.assertEquals(2, revisionToMetadata.size());
 -            Assertions.assertEquals(metadataInfo_222, revisionToMetadata.get("222"));
 -            Assertions.assertEquals(MetadataInfo.EMPTY, revisionToMetadata.get("444"));
 -        }
 -    }
 -
 -    // revision 异常场景。运行中地址通知,拿不到revision就用老版本revision
 -    @Test
 -    public void testRevisionFailureOnNotification() {
 -        Set<String> serviceNames = new HashSet<>();
 -        serviceNames.add("app1");
 -        serviceNames.add("app2");
 -        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
 -
 -        ConcurrentMap tmpProxyMap = MetadataUtils.metadataServiceProxies;
 -
 -        try (MockedStatic<MetadataUtils> mockedMetadataUtils = Mockito.mockStatic(MetadataUtils.class)) {
 -            mockedMetadataUtils.when(() -> MetadataUtils.getMetadataServiceProxy(Mockito.any())).thenReturn(metadataService);
 -
 -            // notify app1 instance change
 -            ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent("app1", app1Instances);
 -            listener.onEvent(event);
 -
 -            Mockito.when(metadataService.getMetadataInfo("222")).thenAnswer(new Answer<MetadataInfo>() {
 -                @Override
 -                public MetadataInfo answer(InvocationOnMock invocationOnMock) throws Throwable {
 -                    if (Thread.currentThread().getName().contains("Dubbo-metadata-retry")) {
 -                        return metadataInfo_222;
 -                    }
 -                    return null;
 -                }
 -            });
 -//            Mockito.when(metadataService.getMetadataInfo("444")).thenAnswer(new Answer<MetadataInfo>() {
 +//package org.apache.dubbo.registry.client.event.listener;
 +//
 +//import org.apache.dubbo.common.URL;
 +//import org.apache.dubbo.common.utils.StringUtils;
 +//import org.apache.dubbo.metadata.MetadataInfo;
 +//import org.apache.dubbo.metadata.MetadataService;
 +//import org.apache.dubbo.registry.NotifyListener;
 +//import org.apache.dubbo.registry.client.DefaultServiceInstance;
 +//import org.apache.dubbo.registry.client.InstanceAddressURL;
 +//import org.apache.dubbo.registry.client.ServiceDiscovery;
 +//import org.apache.dubbo.registry.client.ServiceInstance;
 +//import org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;
 +//import org.apache.dubbo.registry.client.metadata.MetadataUtils;
 +//
 +//import com.google.gson.Gson;
++//import org.apache.dubbo.rpc.model.ApplicationModel;
 +//import org.hamcrest.Matchers;
++//import org.junit.jupiter.api.AfterEach;
 +//import org.junit.jupiter.api.Assertions;
 +//import org.junit.jupiter.api.BeforeAll;
 +//import org.junit.jupiter.api.MethodOrderer;
 +//import org.junit.jupiter.api.Order;
 +//import org.junit.jupiter.api.Test;
 +//import org.junit.jupiter.api.TestMethodOrder;
 +//import org.mockito.ArgumentCaptor;
 +//import org.mockito.MockedStatic;
 +//import org.mockito.Mockito;
 +//import org.mockito.invocation.InvocationOnMock;
 +//import org.mockito.stubbing.Answer;
 +//
 +//import java.util.ArrayList;
 +//import java.util.Collections;
 +//import java.util.HashMap;
 +//import java.util.HashSet;
 +//import java.util.List;
 +//import java.util.Map;
 +//import java.util.Set;
 +//import java.util.concurrent.ConcurrentMap;
 +//import java.util.concurrent.ThreadLocalRandom;
 +//
 +//import static org.apache.dubbo.common.constants.CommonConstants.REVISION_KEY;
 +//import static org.apache.dubbo.common.utils.CollectionUtils.isEmpty;
 +//import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.EXPORTED_SERVICES_REVISION_PROPERTY_NAME;
 +//import static org.hamcrest.MatcherAssert.assertThat;
 +//import static org.junit.jupiter.api.Assertions.assertTrue;
 +//import static org.mockito.ArgumentMatchers.eq;
 +//
 +///**
 +// * {@link ServiceInstancesChangedListener} Test
 +// *
 +// * @since 2.7.5
 +// */
 +//@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
 +//public class ServiceInstancesChangedListenerTest {
 +//    private static Gson gson = new Gson();
 +//
 +//    static List<ServiceInstance> app1Instances;
 +//    static List<ServiceInstance> app2Instances;
 +//    static List<ServiceInstance> app1FailedInstances;
 +//    static List<ServiceInstance> app1FailedInstances2;
 +//    static List<ServiceInstance> app1InstancesWithNoRevision;
 +//
 +//    static String metadata_111 = "{\"app\":\"app1\",\"revision\":\"111\",\"services\":{"
 +//        + "\"org.apache.dubbo.demo.DemoService:dubbo\":{\"name\":\"org.apache.dubbo.demo.DemoService\",\"protocol\":\"dubbo\",\"path\":\"org.apache.dubbo.demo.DemoService\",\"params\":{\"side\":\"provider\",\"release\":\"\",\"methods\":\"sayHello,sayHelloAsync\",\"deprecated\":\"false\",\"dubbo\":\"2.0.2\",\"pid\":\"72723\",\"interface\":\"org.apache.dubbo.demo.DemoService\",\"service-name-mapping\":\"true\",\"timeout\":\"3000\",\"generic\":\"false\",\"metadata-type\":\"remote\",\"del [...]
 +//        + "}}";
 +//    static String metadata_222 = "{\"app\":\"app2\",\"revision\":\"333\",\"services\":{"
 +//        + "\"org.apache.dubbo.demo.DemoService:dubbo\":{\"name\":\"org.apache.dubbo.demo.DemoService\",\"protocol\":\"dubbo\",\"path\":\"org.apache.dubbo.demo.DemoService\",\"params\":{\"side\":\"provider\",\"release\":\"\",\"methods\":\"sayHello,sayHelloAsync\",\"deprecated\":\"false\",\"dubbo\":\"2.0.2\",\"pid\":\"72723\",\"interface\":\"org.apache.dubbo.demo.DemoService\",\"service-name-mapping\":\"true\",\"timeout\":\"3000\",\"generic\":\"false\",\"metadata-type\":\"remote\",\"del [...]
 +//        + "\"org.apache.dubbo.demo.DemoService2:dubbo\":{\"name\":\"org.apache.dubbo.demo.DemoService2\",\"protocol\":\"dubbo\",\"path\":\"org.apache.dubbo.demo.DemoService2\",\"params\":{\"side\":\"provider\",\"release\":\"\",\"methods\":\"sayHello,sayHelloAsync\",\"deprecated\":\"false\",\"dubbo\":\"2.0.2\",\"pid\":\"72723\",\"interface\":\"org.apache.dubbo.demo.DemoService2\",\"service-name-mapping\":\"true\",\"timeout\":\"3000\",\"generic\":\"false\",\"metadata-type\":\"remote\",\ [...]
 +//        + "}}";
 +//    static String metadata_333 = "{\"app\":\"app2\",\"revision\":\"333\",\"services\":{"
 +//        + "\"org.apache.dubbo.demo.DemoService:dubbo\":{\"name\":\"org.apache.dubbo.demo.DemoService\",\"protocol\":\"dubbo\",\"path\":\"org.apache.dubbo.demo.DemoService\",\"params\":{\"side\":\"provider\",\"release\":\"\",\"methods\":\"sayHello,sayHelloAsync\",\"deprecated\":\"false\",\"dubbo\":\"2.0.2\",\"pid\":\"72723\",\"interface\":\"org.apache.dubbo.demo.DemoService\",\"service-name-mapping\":\"true\",\"timeout\":\"3000\",\"generic\":\"false\",\"metadata-type\":\"remote\",\"del [...]
 +//        + "\"org.apache.dubbo.demo.DemoService2:dubbo\":{\"name\":\"org.apache.dubbo.demo.DemoService2\",\"protocol\":\"dubbo\",\"path\":\"org.apache.dubbo.demo.DemoService2\",\"params\":{\"side\":\"provider\",\"release\":\"\",\"methods\":\"sayHello,sayHelloAsync\",\"deprecated\":\"false\",\"dubbo\":\"2.0.2\",\"pid\":\"72723\",\"interface\":\"org.apache.dubbo.demo.DemoService2\",\"service-name-mapping\":\"true\",\"timeout\":\"3000\",\"generic\":\"false\",\"metadata-type\":\"remote\",\ [...]
 +//        + "\"org.apache.dubbo.demo.DemoService3:dubbo\":{\"name\":\"org.apache.dubbo.demo.DemoService3\",\"protocol\":\"dubbo\",\"path\":\"org.apache.dubbo.demo.DemoService3\",\"params\":{\"side\":\"provider\",\"release\":\"\",\"methods\":\"sayHello,sayHelloAsync\",\"deprecated\":\"false\",\"dubbo\":\"2.0.2\",\"pid\":\"72723\",\"interface\":\"org.apache.dubbo.demo.DemoService3\",\"service-name-mapping\":\"true\",\"timeout\":\"3000\",\"generic\":\"false\",\"metadata-type\":\"remote\",\ [...]
 +//        + "}}";
 +//    // failed
 +//    static String metadata_444 = "{\"app\":\"app1\",\"revision\":\"444\",\"services\":{"
 +//        + "\"org.apache.dubbo.demo.DemoService:dubbo\":{\"name\":\"org.apache.dubbo.demo.DemoService\",\"protocol\":\"dubbo\",\"path\":\"org.apache.dubbo.demo.DemoService\",\"params\":{\"side\":\"provider\",\"release\":\"\",\"methods\":\"sayHello,sayHelloAsync\",\"deprecated\":\"false\",\"dubbo\":\"2.0.2\",\"pid\":\"72723\",\"interface\":\"org.apache.dubbo.demo.DemoService\",\"service-name-mapping\":\"true\",\"timeout\":\"3000\",\"generic\":\"false\",\"metadata-type\":\"remote\",\"del [...]
 +//        + "}}";
 +//
 +//    static String bad_metadatainfo = "{\"xxx\":\"yyy\"}";
 +//
 +//    static String service1 = "org.apache.dubbo.demo.DemoService";
 +//    static String service2 = "org.apache.dubbo.demo.DemoService2";
 +//    static String service3 = "org.apache.dubbo.demo.DemoService3";
 +//
 +//    static URL consumerURL = URL.valueOf("dubbo://127.0.0.1/org.apache.dubbo.demo.DemoService?registry_cluster=default");
++//    static URL registryURL = URL.valueOf("dubbo://127.0.0.1:2181/org.apache.dubbo.demo.RegistryService");
 +//
 +//    static MetadataInfo metadataInfo_111;
 +//    static MetadataInfo metadataInfo_222;
 +//    static MetadataInfo metadataInfo_333;
 +//    static MetadataInfo metadataInfo_444;
 +//
 +//    static MetadataService metadataService;
 +//
 +//    static ServiceDiscovery serviceDiscovery;
 +//
++//    ServiceInstancesChangedListener listener = null;
++//
 +//    @BeforeAll
 +//    public static void setUp() {
 +//        List<Object> urlsSameRevision = new ArrayList<>();
 +//        urlsSameRevision.add("127.0.0.1:20880?revision=111");
 +//        urlsSameRevision.add("127.0.0.2:20880?revision=111");
 +//        urlsSameRevision.add("127.0.0.3:20880?revision=111");
 +//
 +//        List<Object> urlsDifferentRevision = new ArrayList<>();
 +//        urlsDifferentRevision.add("30.10.0.1:20880?revision=222");
 +//        urlsDifferentRevision.add("30.10.0.2:20880?revision=222");
 +//        urlsDifferentRevision.add("30.10.0.3:20880?revision=333");
 +//        urlsDifferentRevision.add("30.10.0.4:20880?revision=333");
 +//
 +//        List<Object> urlsFailedRevision = new ArrayList<>();
 +//        urlsFailedRevision.add("30.10.0.5:20880?revision=222");
 +//        urlsFailedRevision.add("30.10.0.6:20880?revision=222");
 +//        urlsFailedRevision.add("30.10.0.7:20880?revision=444");// revision will fail
 +//        urlsFailedRevision.add("30.10.0.8:20880?revision=444");// revision will fail
 +//
 +//        List<Object> urlsFailedRevision2 = new ArrayList<>();
 +//        urlsFailedRevision2.add("30.10.0.1:20880?revision=222");
 +//        urlsFailedRevision2.add("30.10.0.2:20880?revision=222");
 +//
 +//        List<Object> urlsWithoutRevision = new ArrayList<>();
 +//        urlsWithoutRevision.add("30.10.0.1:20880");
 +//
 +//        app1Instances = buildInstances(urlsSameRevision);
 +//        app2Instances = buildInstances(urlsDifferentRevision);
 +//        app1FailedInstances = buildInstances(urlsFailedRevision);
 +//        app1FailedInstances2 = buildInstances(urlsFailedRevision2);
 +//        app1InstancesWithNoRevision = buildInstances(urlsWithoutRevision);
 +//
 +//        metadataInfo_111 = gson.fromJson(metadata_111, MetadataInfo.class);
 +//        metadataInfo_222 = gson.fromJson(metadata_222, MetadataInfo.class);
 +//        metadataInfo_333 = gson.fromJson(metadata_333, MetadataInfo.class);
 +//        metadataInfo_444 = gson.fromJson(metadata_444, MetadataInfo.class);
 +//
 +//        metadataService = Mockito.mock(MetadataService.class);
 +//        Mockito.doReturn(metadataInfo_111).when(metadataService).getMetadataInfo("111");
 +//        Mockito.doReturn(metadataInfo_222).when(metadataService).getMetadataInfo("222");
 +//        Mockito.doReturn(metadataInfo_333).when(metadataService).getMetadataInfo("333");
 +//        Mockito.doThrow(IllegalStateException.class).when(metadataService).getMetadataInfo("444");
 +//
 +//        serviceDiscovery = Mockito.mock(ServiceDiscovery.class);
++//        Mockito.doReturn(registryURL).when(serviceDiscovery).getUrl();
++//    }
++//
++//    @AfterEach
++//    public void tearDown() {
++//        if (listener != null) {
++//            listener.destroy();
++//            listener = null;
++//        }
 +//    }
 +//
 +//    // 正常场景。单应用app1 通知地址基本流程,只做instance-metadata关联,没有metadata内容的解析
 +//    @Test
 +//    @Order(1)
 +//    public void testInstanceNotification() {
 +//        Set<String> serviceNames = new HashSet<>();
 +//        serviceNames.add("app1");
 +//        ServiceDiscovery serviceDiscovery = Mockito.mock(ServiceDiscovery.class);
- //        ServiceInstancesChangedListener spyListener = Mockito.spy(new ServiceInstancesChangedListener(serviceNames, serviceDiscovery));
++//        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
++//        ServiceInstancesChangedListener spyListener = Mockito.spy(listener);
 +//        Mockito.doReturn(metadataInfo_111).when(spyListener).getRemoteMetadata(eq("111"), Mockito.anyMap(), Mockito.any());
 +//        ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent("app1", app1Instances);
 +//        spyListener.onEvent(event);
 +//
 +//        Map<String, List<ServiceInstance>> allInstances = spyListener.getAllInstances();
 +//        Assertions.assertEquals(1, allInstances.size());
 +//        Assertions.assertEquals(3, allInstances.get("app1").size());
 +//
 +//        Map<String, MetadataInfo> revisionToMetadata = spyListener.getRevisionToMetadata();
 +//        Assertions.assertEquals(1, revisionToMetadata.size());
 +//        Assertions.assertEquals(metadataInfo_111, revisionToMetadata.get("111"));
 +//
 +////        // test app2 notification
 +////        Mockito.doReturn(metadataInfo_222).when(spyListener).getRemoteMetadata(eq("222"), Mockito.anyMap(), Mockito.anyList());
 +////        Mockito.doReturn(metadataInfo_333).when(spyListener).getRemoteMetadata(eq("333"), Mockito.anyMap(), Mockito.anyList());
 +////
 +////        ServiceInstancesChangedEvent event_app2 = new ServiceInstancesChangedEvent("app2", app2Instances);
 +////        spyListener.onEvent(event_app2);
 +//
 +//    }
 +//
 +//    // 正常场景。单应用app1,进一步检查 metadata service 是否正确映射
 +//    @Test
 +//    @Order(2)
 +//    public void testInstanceNotificationAndMetadataParse() {
 +//        Set<String> serviceNames = new HashSet<>();
 +//        serviceNames.add("app1");
- //        ServiceInstancesChangedListener listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
++//        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
 +//
 +//        try (MockedStatic<MetadataUtils> mockedMetadataUtils = Mockito.mockStatic(MetadataUtils.class)) {
 +//            mockedMetadataUtils.when(() -> MetadataUtils.getMetadataServiceProxy(Mockito.any())).thenReturn(metadataService);
 +//            // notify instance change
 +//            ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent("app1", app1Instances);
 +//            listener.onEvent(event);
 +//
 +//            Map<String, List<ServiceInstance>> allInstances = listener.getAllInstances();
 +//            Assertions.assertEquals(1, allInstances.size());
 +//            Assertions.assertEquals(3, allInstances.get("app1").size());
 +//
 +//            Map<String, MetadataInfo> revisionToMetadata = listener.getRevisionToMetadata();
 +//            Assertions.assertEquals(1, revisionToMetadata.size());
 +//            Assertions.assertEquals(metadataInfo_111, revisionToMetadata.get("111"));
 +//
 +//            List<URL> serviceUrls = listener.getAddresses(service1 + ":dubbo", consumerURL);
 +//            Assertions.assertEquals(3, serviceUrls.size());
 +//            assertTrue(serviceUrls.get(0) instanceof InstanceAddressURL);
 +//
 +//            assertThat(serviceUrls, Matchers.hasItem(Matchers.hasProperty("instance", Matchers.notNullValue())));
 +//            assertThat(serviceUrls, Matchers.hasItem(Matchers.hasProperty("metadataInfo", Matchers.notNullValue())));
 +//
 +//        }
 +//    }
 +//
 +//    // 正常场景。多应用,app1 app2 分别通知地址
 +//    @Test
 +//    @Order(3)
 +//    public void testMultipleAppNotification() {
 +//        Set<String> serviceNames = new HashSet<>();
 +//        serviceNames.add("app1");
 +//        serviceNames.add("app2");
- //        ServiceInstancesChangedListener listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
++//        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
 +//
 +//        try (MockedStatic<MetadataUtils> mockedMetadataUtils = Mockito.mockStatic(MetadataUtils.class)) {
 +//            mockedMetadataUtils.when(() -> MetadataUtils.getMetadataServiceProxy(Mockito.any())).thenReturn(metadataService);
 +//            // notify app1 instance change
 +//            ServiceInstancesChangedEvent app1_event = new ServiceInstancesChangedEvent("app1", app1Instances);
 +//            listener.onEvent(app1_event);
 +//
 +//            // notify app2 instance change
 +//            ServiceInstancesChangedEvent app2_event = new ServiceInstancesChangedEvent("app2", app2Instances);
 +//            listener.onEvent(app2_event);
 +//
 +//            // check
 +//            Map<String, List<ServiceInstance>> allInstances = listener.getAllInstances();
 +//            Assertions.assertEquals(2, allInstances.size());
 +//            Assertions.assertEquals(3, allInstances.get("app1").size());
 +//            Assertions.assertEquals(4, allInstances.get("app2").size());
 +//
 +//            Map<String, MetadataInfo> revisionToMetadata = listener.getRevisionToMetadata();
 +//            Assertions.assertEquals(3, revisionToMetadata.size());
 +//            Assertions.assertEquals(metadataInfo_111, revisionToMetadata.get("111"));
 +//            Assertions.assertEquals(metadataInfo_222, revisionToMetadata.get("222"));
 +//            Assertions.assertEquals(metadataInfo_333, revisionToMetadata.get("333"));
 +//
 +//            List<URL> serviceUrls = listener.getAddresses(service1 + ":dubbo", consumerURL);
 +//            Assertions.assertEquals(7, serviceUrls.size());
 +//            List<URL> serviceUrls2 = listener.getAddresses(service2 + ":dubbo", consumerURL);
 +//            Assertions.assertEquals(4, serviceUrls2.size());
 +//            assertTrue(serviceUrls2.get(0).getIp().contains("30.10."));
 +//            List<URL> serviceUrls3 = listener.getAddresses(service3 + ":dubbo", consumerURL);
 +//            Assertions.assertEquals(2, serviceUrls3.size());
 +//            assertTrue(serviceUrls3.get(0).getIp().contains("30.10."));
 +//        }
 +//    }
 +//
 +//    // 正常场景。多应用,app1 app2,空地址通知(边界条件)能否解析出正确的空地址列表
 +//    @Test
 +//    @Order(4)
 +//    public void testMultipleAppEmptyNotification() {
 +//        Set<String> serviceNames = new HashSet<>();
 +//        serviceNames.add("app1");
 +//        serviceNames.add("app2");
- //        ServiceInstancesChangedListener listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
++//        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
 +//
 +//        try (MockedStatic<MetadataUtils> mockedMetadataUtils = Mockito.mockStatic(MetadataUtils.class)) {
 +//            mockedMetadataUtils.when(() -> MetadataUtils.getMetadataServiceProxy(Mockito.any())).thenReturn(metadataService);
 +//            // notify app1 instance change
 +//            ServiceInstancesChangedEvent app1_event = new ServiceInstancesChangedEvent("app1", app1Instances);
 +//            listener.onEvent(app1_event);
 +//
 +//            // notify app2 instance change
 +//            ServiceInstancesChangedEvent app2_event = new ServiceInstancesChangedEvent("app2", app2Instances);
 +//            listener.onEvent(app2_event);
 +//
 +//            // empty notification
 +//            ServiceInstancesChangedEvent app1_event_again = new ServiceInstancesChangedEvent("app1", Collections.EMPTY_LIST);
 +//            listener.onEvent(app1_event_again);
 +//
 +//            // check app1 cleared
 +//            Map<String, List<ServiceInstance>> allInstances = listener.getAllInstances();
 +//            Assertions.assertEquals(2, allInstances.size());
 +//            Assertions.assertEquals(0, allInstances.get("app1").size());
 +//            Assertions.assertEquals(4, allInstances.get("app2").size());
 +//
 +//            Map<String, MetadataInfo> revisionToMetadata = listener.getRevisionToMetadata();
 +//            Assertions.assertEquals(2, revisionToMetadata.size());
 +//            Assertions.assertNull(revisionToMetadata.get("111"));
 +//            Assertions.assertEquals(metadataInfo_222, revisionToMetadata.get("222"));
 +//            Assertions.assertEquals(metadataInfo_333, revisionToMetadata.get("333"));
 +//
 +//            List<URL> serviceUrls = listener.getAddresses(service1 + ":dubbo", consumerURL);
 +//            Assertions.assertEquals(4, serviceUrls.size());
 +//            assertTrue(serviceUrls.get(0).getIp().contains("30.10."));
 +//            List<URL> serviceUrls2 = listener.getAddresses(service2 + ":dubbo", consumerURL);
 +//            Assertions.assertEquals(4, serviceUrls2.size());
 +//            assertTrue(serviceUrls2.get(0).getIp().contains("30.10."));
 +//            List<URL> serviceUrls3 = listener.getAddresses(service3 + ":dubbo", consumerURL);
 +//            Assertions.assertEquals(2, serviceUrls3.size());
 +//            assertTrue(serviceUrls3.get(0).getIp().contains("30.10."));
 +//
 +//            // app2 empty notification
 +//            ServiceInstancesChangedEvent app2_event_again = new ServiceInstancesChangedEvent("app2", Collections.EMPTY_LIST);
 +//            listener.onEvent(app2_event_again);
 +//
 +//            // check app2 cleared
 +//            Map<String, List<ServiceInstance>> allInstances_app2 = listener.getAllInstances();
 +//            Assertions.assertEquals(2, allInstances_app2.size());
 +//            Assertions.assertEquals(0, allInstances_app2.get("app1").size());
 +//            Assertions.assertEquals(0, allInstances_app2.get("app2").size());
 +//
 +//            Map<String, MetadataInfo> revisionToMetadata_app2 = listener.getRevisionToMetadata();
 +//            Assertions.assertEquals(0, revisionToMetadata_app2.size());
 +//
 +//            assertTrue(isEmpty(listener.getAddresses(service1 + ":dubbo", consumerURL)));
- //            assertTrue(isEmpty(listener.getAddresses(service2+ ":dubbo", consumerURL)));
++//            assertTrue(isEmpty(listener.getAddresses(service2 + ":dubbo", consumerURL)));
 +//            assertTrue(isEmpty(listener.getAddresses(service3 + ":dubbo", consumerURL)));
 +//        }
 +//    }
 +//
 +//    // 正常场景。检查instance listener -> service listener(Directory)地址推送流程
 +//    @Test
 +//    @Order(5)
 +//    public void testServiceListenerNotification() {
 +//        Set<String> serviceNames = new HashSet<>();
 +//        serviceNames.add("app1");
 +//        serviceNames.add("app2");
- //        ServiceInstancesChangedListener listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
++//        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
 +//        NotifyListener demoServiceListener = Mockito.mock(NotifyListener.class);
 +//        NotifyListener demoService2Listener = Mockito.mock(NotifyListener.class);
 +//        listener.addListenerAndNotify(service1 + ":dubbo", demoServiceListener);
 +//        listener.addListenerAndNotify(service2 + ":dubbo", demoService2Listener);
 +//
 +//        try (MockedStatic<MetadataUtils> mockedMetadataUtils = Mockito.mockStatic(MetadataUtils.class)) {
 +//            mockedMetadataUtils.when(() -> MetadataUtils.getMetadataServiceProxy(Mockito.any())).thenReturn(metadataService);
 +//            // notify app1 instance change
 +//            ServiceInstancesChangedEvent app1_event = new ServiceInstancesChangedEvent("app1", app1Instances);
 +//            listener.onEvent(app1_event);
 +//
 +//            // check
 +//            ArgumentCaptor<List<URL>> captor = ArgumentCaptor.forClass(List.class);
 +//            Mockito.verify(demoServiceListener, Mockito.times(1)).notify(captor.capture());
 +//            List<URL> notifiedUrls = captor.getValue();
 +//            Assertions.assertEquals(3, notifiedUrls.size());
 +//            ArgumentCaptor<List<URL>> captor2 = ArgumentCaptor.forClass(List.class);
 +//            Mockito.verify(demoService2Listener, Mockito.times(1)).notify(captor2.capture());
 +//            List<URL> notifiedUrls2 = captor2.getValue();
 +//            Assertions.assertEquals(0, notifiedUrls2.size());
 +//
 +//            // notify app2 instance change
 +//            ServiceInstancesChangedEvent app2_event = new ServiceInstancesChangedEvent("app2", app2Instances);
 +//            listener.onEvent(app2_event);
 +//
 +//            // check
 +//            ArgumentCaptor<List<URL>> app2_captor = ArgumentCaptor.forClass(List.class);
 +//            Mockito.verify(demoServiceListener, Mockito.times(2)).notify(app2_captor.capture());
 +//            List<URL> app2_notifiedUrls = app2_captor.getValue();
 +//            Assertions.assertEquals(7, app2_notifiedUrls.size());
 +//            ArgumentCaptor<List<URL>> app2_captor2 = ArgumentCaptor.forClass(List.class);
 +//            Mockito.verify(demoService2Listener, Mockito.times(2)).notify(app2_captor2.capture());
 +//            List<URL> app2_notifiedUrls2 = app2_captor2.getValue();
 +//            Assertions.assertEquals(4, app2_notifiedUrls2.size());
 +//        }
 +//
 +//        // test service listener still get notified when added after instance notification.
 +//        NotifyListener demoService3Listener = Mockito.mock(NotifyListener.class);
 +//        listener.addListenerAndNotify(service3 + ":dubbo", demoService3Listener);
 +//        Mockito.verify(demoService3Listener, Mockito.times(1)).notify(Mockito.anyList());
 +//    }
 +//
 +//    // revision 异常场景。第一次启动,完全拿不到metadata,只能通知部分地址
 +//    @Test
 +//    @Order(6)
 +//    public void testRevisionFailureOnStartup() {
 +//        Set<String> serviceNames = new HashSet<>();
 +//        serviceNames.add("app1");
- //        ServiceInstancesChangedListener listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
++//        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
 +//        try (MockedStatic<MetadataUtils> mockedMetadataUtils = Mockito.mockStatic(MetadataUtils.class)) {
 +//            mockedMetadataUtils.when(() -> MetadataUtils.getMetadataServiceProxy(Mockito.any())).thenReturn(metadataService);
 +//            // notify app1 instance change
 +//            ServiceInstancesChangedEvent failed_revision_event = new ServiceInstancesChangedEvent("app1", app1FailedInstances);
 +//            listener.onEvent(failed_revision_event);
 +//
 +//            List<URL> serviceUrls = listener.getAddresses(service1 + ":dubbo", consumerURL);
 +//            List<URL> serviceUrls2 = listener.getAddresses(service2 + ":dubbo", consumerURL);
 +//
 +//            assertTrue(isEmpty(serviceUrls));
 +//            assertTrue(isEmpty(serviceUrls2));
 +//
 +//            Map<String, MetadataInfo> revisionToMetadata = listener.getRevisionToMetadata();
 +//            Assertions.assertEquals(2, revisionToMetadata.size());
 +//            Assertions.assertEquals(metadataInfo_222, revisionToMetadata.get("222"));
 +//            Assertions.assertEquals(MetadataInfo.EMPTY, revisionToMetadata.get("444"));
 +//        }
 +//    }
 +//
 +//    // revision 异常场景。运行中地址通知,拿不到revision就用老版本revision
 +//    @Test
 +//    public void testRevisionFailureOnNotification() {
 +//        Set<String> serviceNames = new HashSet<>();
 +//        serviceNames.add("app1");
 +//        serviceNames.add("app2");
- //        ServiceInstancesChangedListener listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
++//        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
 +//
 +//        ConcurrentMap tmpProxyMap = MetadataUtils.metadataServiceProxies;
 +//
 +//        try (MockedStatic<MetadataUtils> mockedMetadataUtils = Mockito.mockStatic(MetadataUtils.class)) {
 +//            mockedMetadataUtils.when(() -> MetadataUtils.getMetadataServiceProxy(Mockito.any())).thenReturn(metadataService);
 +//
 +//            // notify app1 instance change
 +//            ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent("app1", app1Instances);
 +//            listener.onEvent(event);
 +//
 +//            Mockito.when(metadataService.getMetadataInfo("222")).thenAnswer(new Answer<MetadataInfo>() {
  //                @Override
  //                public MetadataInfo answer(InvocationOnMock invocationOnMock) throws Throwable {
  //                    if (Thread.currentThread().getName().contains("Dubbo-metadata-retry")) {
@@@ -423,100 -447,93 +438,102 @@@
  //                    return null;
  //                }
  //            });
 -
 -            ServiceInstancesChangedEvent event2 = new ServiceInstancesChangedEvent("app2", app1FailedInstances2);
 -            listener.onEvent(event2);
 -
 -            // FIXME, manually mock proxy util, for retry task will work on another thread which makes MockStatic useless.
 -            ConcurrentMap map = Mockito.mock(ConcurrentMap.class);
 -            Mockito.doReturn(metadataService).when(map).get(Mockito.any());
 -            Mockito.doReturn(metadataService).when(map).computeIfAbsent(Mockito.any(), Mockito.any());
 -            MetadataUtils.metadataServiceProxies = map;
 -
 -            // event2 did not really take effect
 -            Map<String, MetadataInfo> revisionToMetadata = listener.getRevisionToMetadata();
 -            Assertions.assertEquals(2, revisionToMetadata.size());
 -            Assertions.assertEquals(metadataInfo_111, revisionToMetadata.get("111"));
 -            Assertions.assertEquals(MetadataInfo.EMPTY, revisionToMetadata.get("222"));
 -
 -            Assertions.assertEquals(3, listener.getAddresses(service1 + ":dubbo", consumerURL).size());
 -            assertTrue(isEmpty(listener.getAddresses(service2 + ":dubbo", consumerURL)));
 -
 -            try {
 -                Thread.sleep(15000);
 -            } catch (InterruptedException e) {
 -                e.printStackTrace();
 -            }
 -            // check recovered after retry.
 -            Map<String, MetadataInfo> revisionToMetadata_after_retry = listener.getRevisionToMetadata();
 -            Assertions.assertEquals(2, revisionToMetadata_after_retry.size());
 -            Assertions.assertEquals(metadataInfo_111, revisionToMetadata_after_retry.get("111"));
 -            Assertions.assertEquals(metadataInfo_222, revisionToMetadata_after_retry.get("222"));
 -
 -            List<URL> serviceUrls_after_retry = listener.getAddresses(service1 + ":dubbo", consumerURL);
 -            Assertions.assertEquals(5, serviceUrls_after_retry.size());
 -            List<URL> serviceUrls2_after_retry = listener.getAddresses(service2 + ":dubbo", consumerURL);
 -            Assertions.assertEquals(2, serviceUrls2_after_retry.size());
 -        } finally {
 -            MetadataUtils.metadataServiceProxies = tmpProxyMap;
 -        }
 -    }
 -
 -    // Abnormal case. Instance does not has revision
 -    @Test
 -    public void testInstanceWithoutRevision() {
 -        Set<String> serviceNames = new HashSet<>();
 -        serviceNames.add("app1");
 -        ServiceDiscovery serviceDiscovery = Mockito.mock(ServiceDiscovery.class);
 -        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
 -        ServiceInstancesChangedListener spyListener = Mockito.spy(listener);
 -        Mockito.doReturn(null).when(spyListener).getRemoteMetadata(eq(null), Mockito.anyMap(), Mockito.any());
 -        ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent("app1", app1InstancesWithNoRevision);
 -        spyListener.onEvent(event);
 -        // notification succeeded
 -        assertTrue(true);
 -    }
 -
 -    @Test
 -    public void testSelectInstance() {
 -        System.out.println(ThreadLocalRandom.current().nextInt(0, 100));
 -        System.out.println(ThreadLocalRandom.current().nextInt(0, 100));
 -        System.out.println(ThreadLocalRandom.current().nextInt(0, 100));
 -        System.out.println(ThreadLocalRandom.current().nextInt(0, 100));
 -        System.out.println(ThreadLocalRandom.current().nextInt(0, 100));
 -    }
 -
 -    static List<ServiceInstance> buildInstances(List<Object> rawURls) {
 -        List<ServiceInstance> instances = new ArrayList<>();
 -
 -        for (Object obj : rawURls) {
 -            String rawURL = (String) obj;
 -            DefaultServiceInstance instance = new DefaultServiceInstance();
 -            final URL dubboUrl = URL.valueOf(rawURL);
 -            instance.setRawAddress(rawURL);
 -            instance.setHost(dubboUrl.getHost());
 -            instance.setEnabled(true);
 -            instance.setHealthy(true);
 -            instance.setPort(dubboUrl.getPort());
 -            instance.setRegistryCluster("default");
 -            instance.setApplicationModel(ApplicationModel.defaultModel());
 -
 -            Map<String, String> metadata = new HashMap<>();
 -            if (StringUtils.isNotEmpty(dubboUrl.getParameter(REVISION_KEY))) {
 -                metadata.put(EXPORTED_SERVICES_REVISION_PROPERTY_NAME, dubboUrl.getParameter(REVISION_KEY));
 -            }
 -            instance.setMetadata(metadata);
 -
 -            instances.add(instance);
 -        }
 -
 -        return instances;
 -    }
 -}
 +////            Mockito.when(metadataService.getMetadataInfo("444")).thenAnswer(new Answer<MetadataInfo>() {
 +////                @Override
 +////                public MetadataInfo answer(InvocationOnMock invocationOnMock) throws Throwable {
 +////                    if (Thread.currentThread().getName().contains("Dubbo-metadata-retry")) {
 +////                        return metadataInfo_444;
 +////                    }
 +////                    return null;
 +////                }
 +////            });
 +//
 +//            ServiceInstancesChangedEvent event2 = new ServiceInstancesChangedEvent("app2", app1FailedInstances2);
 +//            listener.onEvent(event2);
 +//
 +//            // FIXME, manually mock proxy util, for retry task will work on another thread which makes MockStatic useless.
 +//            ConcurrentMap map = Mockito.mock(ConcurrentMap.class);
 +//            Mockito.doReturn(metadataService).when(map).get(Mockito.any());
 +//            Mockito.doReturn(metadataService).when(map).computeIfAbsent(Mockito.any(), Mockito.any());
 +//            MetadataUtils.metadataServiceProxies = map;
 +//
 +//            // event2 did not really take effect
 +//            Map<String, MetadataInfo> revisionToMetadata = listener.getRevisionToMetadata();
 +//            Assertions.assertEquals(2, revisionToMetadata.size());
 +//            Assertions.assertEquals(metadataInfo_111, revisionToMetadata.get("111"));
 +//            Assertions.assertEquals(MetadataInfo.EMPTY, revisionToMetadata.get("222"));
 +//
 +//            Assertions.assertEquals(3, listener.getAddresses(service1 + ":dubbo", consumerURL).size());
 +//            assertTrue(isEmpty(listener.getAddresses(service2 + ":dubbo", consumerURL)));
 +//
 +//            try {
 +//                Thread.sleep(15000);
 +//            } catch (InterruptedException e) {
 +//                e.printStackTrace();
 +//            }
 +//            // check recovered after retry.
 +//            Map<String, MetadataInfo> revisionToMetadata_after_retry = listener.getRevisionToMetadata();
 +//            Assertions.assertEquals(2, revisionToMetadata_after_retry.size());
 +//            Assertions.assertEquals(metadataInfo_111, revisionToMetadata_after_retry.get("111"));
 +//            Assertions.assertEquals(metadataInfo_222, revisionToMetadata_after_retry.get("222"));
 +//
 +//            List<URL> serviceUrls_after_retry = listener.getAddresses(service1 + ":dubbo", consumerURL);
 +//            Assertions.assertEquals(5, serviceUrls_after_retry.size());
 +//            List<URL> serviceUrls2_after_retry = listener.getAddresses(service2 + ":dubbo", consumerURL);
 +//            Assertions.assertEquals(2, serviceUrls2_after_retry.size());
 +//        } finally {
 +//            MetadataUtils.metadataServiceProxies = tmpProxyMap;
 +//        }
 +//    }
 +//
 +//    // Abnormal case. Instance does not has revision
 +//    @Test
 +//    public void testInstanceWithoutRevision() {
 +//        Set<String> serviceNames = new HashSet<>();
 +//        serviceNames.add("app1");
 +//        ServiceDiscovery serviceDiscovery = Mockito.mock(ServiceDiscovery.class);
- //        ServiceInstancesChangedListener spyListener = Mockito.spy(new ServiceInstancesChangedListener(serviceNames, serviceDiscovery));
++//        listener = new ServiceInstancesChangedListener(serviceNames, serviceDiscovery);
++//        ServiceInstancesChangedListener spyListener = Mockito.spy(listener);
 +//        Mockito.doReturn(null).when(spyListener).getRemoteMetadata(eq(null), Mockito.anyMap(), Mockito.any());
 +//        ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent("app1", app1InstancesWithNoRevision);
 +//        spyListener.onEvent(event);
 +//        // notification succeeded
 +//        assertTrue(true);
 +//    }
 +//
 +//    @Test
 +//    public void testSelectInstance() {
 +//        System.out.println(ThreadLocalRandom.current().nextInt(0, 100));
 +//        System.out.println(ThreadLocalRandom.current().nextInt(0, 100));
 +//        System.out.println(ThreadLocalRandom.current().nextInt(0, 100));
 +//        System.out.println(ThreadLocalRandom.current().nextInt(0, 100));
 +//        System.out.println(ThreadLocalRandom.current().nextInt(0, 100));
 +//    }
 +//
 +//    static List<ServiceInstance> buildInstances(List<Object> rawURls) {
 +//        List<ServiceInstance> instances = new ArrayList<>();
 +//
 +//        for (Object obj : rawURls) {
- //            String rawURL = (String)obj;
++//            String rawURL = (String) obj;
 +//            DefaultServiceInstance instance = new DefaultServiceInstance();
 +//            final URL dubboUrl = URL.valueOf(rawURL);
 +//            instance.setRawAddress(rawURL);
 +//            instance.setHost(dubboUrl.getHost());
 +//            instance.setEnabled(true);
 +//            instance.setHealthy(true);
 +//            instance.setPort(dubboUrl.getPort());
 +//            instance.setRegistryCluster("default");
++//            instance.setApplicationModel(ApplicationModel.defaultModel());
 +//
 +//            Map<String, String> metadata = new HashMap<>();
 +//            if (StringUtils.isNotEmpty(dubboUrl.getParameter(REVISION_KEY))) {
 +//                metadata.put(EXPORTED_SERVICES_REVISION_PROPERTY_NAME, dubboUrl.getParameter(REVISION_KEY));
 +//            }
 +//            instance.setMetadata(metadata);
 +//
 +//            instances.add(instance);
 +//        }
 +//
 +//        return instances;
 +//    }
 +//}
diff --cc dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java
index 3545e6a,eed8192..058c009
--- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java
+++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java
@@@ -639,11 -638,10 +639,12 @@@ public class DubboProtocol extends Abst
  
          ExchangeClient client;
          try {
 +            // Replace InstanceAddressURL with ServiceConfigURL.
-             url = new ServiceConfigURL(url.getProtocol(), url.getUsername(), url.getPassword(), url.getHost(), url.getPort(), url.getPath(), url.getParameters());
++            url = new ServiceConfigURL(DubboCodec.NAME, url.getUsername(), url.getPassword(), url.getHost(), url.getPort(), url.getPath(),  url.getParameters());
              // connection should be lazy
              if (url.getParameter(LAZY_CONNECT_KEY, false)) {
-                 client = new LazyConnectExchangeClient(url, requestHandler);
+                 client = new LazyConnectExchangeClient(url, requestHandler, DubboCodec.NAME, url.getParameters());
+ 
              } else {
                  client = Exchangers.connect(url, requestHandler);
              }
diff --cc dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/LazyConnectExchangeClient.java
index c3abca2,a5bb837..87fba37
--- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/LazyConnectExchangeClient.java
+++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/LazyConnectExchangeClient.java
@@@ -57,11 -59,14 +57,11 @@@ final class LazyConnectExchangeClient i
       */
      private final boolean initialState;
      private volatile ExchangeClient client;
-     private AtomicLong warningCount = new AtomicLong(0);
+     private final AtomicLong warningCount = new AtomicLong(0);
  
 -    public LazyConnectExchangeClient(URL url, ExchangeHandler requestHandler, String codec, Map<String, String> parameters) {
 +    public LazyConnectExchangeClient(URL url, ExchangeHandler requestHandler) {
          // lazy connect, need set send.reconnect = true, to avoid channel bad status.
 -        // Parameters like 'username', 'password' and 'path' are set but will not be used in following processes.
 -        // The most important parameters here are 'host', port', 'parameters' and 'codec', 'codec' can also be extracted from 'parameters'
 -        this.url = new ServiceConfigURL(codec, url.getUsername(), url.getPassword(), url.getHost(), url.getPort(), url.getPath(), parameters)
 -            .addParameter(SEND_RECONNECT_KEY, Boolean.TRUE.toString());
 +        this.url = url.addParameter(SEND_RECONNECT_KEY, Boolean.TRUE.toString());
          this.requestHandler = requestHandler;
          this.initialState = url.getParameter(LAZY_CONNECT_INITIAL_STATE_KEY, DEFAULT_LAZY_CONNECT_INITIAL_STATE);
          this.requestWithWarning = url.getParameter(LAZY_REQUEST_WITH_WARNING_KEY, DEFAULT_LAZY_REQUEST_WITH_WARNING);