feat: refactor client module to resolve circular dependencies (#2399)

diff --git a/client/client.go b/client/client.go
index 9619321..ab93c37 100644
--- a/client/client.go
+++ b/client/client.go
@@ -1,3 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package client
 
 import (
@@ -98,10 +115,7 @@
 }
 
 func NewClient(opts ...ReferenceOption) (*Client, error) {
-	// get default RootConfigs
-	//rootCfg := config.NewRootConfigBuilder().Build()
-	//rootCfg.Init()
-	// todo: create a default ReferenceConfig
+	// todo(DMwangnima): create a default ReferenceConfig
 	newRefCfg := &ReferenceConfig{}
 	if err := newRefCfg.Init(opts...); err != nil {
 		return nil, err
diff --git a/client/compat.go b/client/compat.go
new file mode 100644
index 0000000..f03592c
--- /dev/null
+++ b/client/compat.go
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package client
+
+import (
+	commonCfg "dubbo.apache.org/dubbo-go/v3/common/config"
+	"dubbo.apache.org/dubbo-go/v3/config"
+	"dubbo.apache.org/dubbo-go/v3/registry"
+)
+
+// these functions are used to resolve circular dependencies temporarily.
+// please refer to issue(https://github.com/apache/dubbo-go/issues/2377)
+// todo(DMwangnima): remove these functions when refactoring dubbo-go
+func compatApplicationConfig(c *commonCfg.ApplicationConfig) *config.ApplicationConfig {
+	return &config.ApplicationConfig{
+		Organization: c.Organization,
+		Name:         c.Name,
+		Module:       c.Module,
+		Group:        c.Group,
+		Version:      c.Version,
+		Owner:        c.Owner,
+		Environment:  c.Environment,
+		MetadataType: c.MetadataType,
+		Tag:          c.Tag,
+	}
+}
+
+func compatRegistryConfig(c *registry.RegistryConfig) *config.RegistryConfig {
+	return &config.RegistryConfig{
+		Protocol:          c.Protocol,
+		Timeout:           c.Timeout,
+		Group:             c.Group,
+		Namespace:         c.Namespace,
+		TTL:               c.TTL,
+		Address:           c.Address,
+		Username:          c.Username,
+		Password:          c.Password,
+		Simplified:        c.Simplified,
+		Preferred:         c.Preferred,
+		Zone:              c.Zone,
+		Weight:            c.Weight,
+		Params:            c.Params,
+		RegistryType:      c.RegistryType,
+		UseAsMetaReport:   c.UseAsMetaReport,
+		UseAsConfigCenter: c.UseAsConfigCenter,
+	}
+}
diff --git a/client/options.go b/client/options.go
index cea2e48..aac3202 100644
--- a/client/options.go
+++ b/client/options.go
@@ -1,3 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package client
 
 import (
diff --git a/client/reference_config.go b/client/reference_config.go
index ca75dd7..6e52dae 100644
--- a/client/reference_config.go
+++ b/client/reference_config.go
@@ -40,6 +40,7 @@
 	commonCfg "dubbo.apache.org/dubbo-go/v3/common/config"
 	"dubbo.apache.org/dubbo-go/v3/common/constant"
 	"dubbo.apache.org/dubbo-go/v3/common/extension"
+	"dubbo.apache.org/dubbo-go/v3/config"
 	"dubbo.apache.org/dubbo-go/v3/protocol"
 	"dubbo.apache.org/dubbo-go/v3/protocol/protocolwrapper"
 	"dubbo.apache.org/dubbo-go/v3/proxy"
@@ -84,9 +85,11 @@
 	adaptiveService bool
 	proxyFactory    string
 
-	application *commonCfg.ApplicationConfig
+	application       *commonCfg.ApplicationConfig
+	applicationCompat *config.ApplicationConfig
 
-	registries map[string]*registry.RegistryConfig
+	registries       map[string]*registry.RegistryConfig
+	registriesCompat map[string]*config.RegistryConfig
 }
 
 func (rc *ReferenceConfig) Prefix() string {
@@ -94,30 +97,47 @@
 }
 
 func (rc *ReferenceConfig) Init(opts ...ReferenceOption) error {
-	for _, method := range rc.Methods {
-		if err := method.Init(); err != nil {
-			return err
-		}
-	}
 	if err := defaults.Set(rc); err != nil {
 		return err
 	}
 	for _, opt := range opts {
 		opt(rc)
 	}
-	if rc.application != nil {
-		rc.metaDataType = rc.application.MetadataType
-		if rc.Group == "" {
-			rc.Group = rc.application.Group
-		}
-		if rc.Version == "" {
-			rc.Version = rc.application.Version
+	// init method
+	for _, method := range rc.Methods {
+		if err := method.Init(); err != nil {
+			return err
 		}
 	}
+	// init application
+	if rc.application != nil {
+		rc.applicationCompat = compatApplicationConfig(rc.application)
+		if err := rc.applicationCompat.Init(); err != nil {
+			return err
+		}
+		rc.metaDataType = rc.applicationCompat.MetadataType
+		if rc.Group == "" {
+			rc.Group = rc.applicationCompat.Group
+		}
+		if rc.Version == "" {
+			rc.Version = rc.applicationCompat.Version
+		}
+	}
+	// init cluster
 	if rc.Cluster == "" {
 		rc.Cluster = "failover"
 	}
 	// todo: move to registry package
+	// init registries
+	if rc.registries != nil {
+		rc.registriesCompat = make(map[string]*config.RegistryConfig)
+		for key, reg := range rc.registries {
+			rc.registriesCompat[key] = compatRegistryConfig(reg)
+			if err := rc.registriesCompat[key].Init(); err != nil {
+				return err
+			}
+		}
+	}
 	rc.RegistryIDs = commonCfg.TranslateIds(rc.RegistryIDs)
 
 	return commonCfg.Verify(rc)
@@ -158,16 +178,20 @@
 	rc.URL = "tri://" + rc.ProvidedBy + "." + podNamespace + constant.SVC + clusterDomain + ":" + strconv.Itoa(meshPort)
 }
 
-// Refer retrieves invokers from urls.
-func (rc *ReferenceConfig) Refer(srv interface{}) {
-	rc.refer(nil, srv)
+// ReferWithService retrieves invokers from urls.
+func (rc *ReferenceConfig) ReferWithService(srv common.RPCService) {
+	rc.refer(srv, nil)
 }
 
 func (rc *ReferenceConfig) ReferWithInfo(info *ClientInfo) {
-	rc.refer(info, nil)
+	rc.refer(nil, info)
 }
 
-func (rc *ReferenceConfig) refer(info *ClientInfo, srv interface{}) {
+func (rc *ReferenceConfig) ReferWithServiceAndInfo(srv common.RPCService, info *ClientInfo) {
+	rc.refer(srv, info)
+}
+
+func (rc *ReferenceConfig) refer(srv common.RPCService, info *ClientInfo) {
 	var methods []string
 	if info != nil {
 		rc.InterfaceName = info.InterfaceName
@@ -236,7 +260,7 @@
 			}
 		}
 	} else { // use registry configs
-		rc.urls = registry.LoadRegistries(rc.RegistryIDs, rc.registries, common.CONSUMER)
+		rc.urls = config.LoadRegistries(rc.RegistryIDs, rc.registriesCompat, common.CONSUMER)
 		// set url to regURLs
 		for _, regURL := range rc.urls {
 			regURL.SubURL = cfgURL
@@ -382,14 +406,14 @@
 	urlMap.Set(constant.StickyKey, strconv.FormatBool(rc.Sticky))
 
 	// applicationConfig info
-	if rc.application != nil {
-		urlMap.Set(constant.ApplicationKey, rc.application.Name)
-		urlMap.Set(constant.OrganizationKey, rc.application.Organization)
-		urlMap.Set(constant.NameKey, rc.application.Name)
-		urlMap.Set(constant.ModuleKey, rc.application.Module)
-		urlMap.Set(constant.AppVersionKey, rc.application.Version)
-		urlMap.Set(constant.OwnerKey, rc.application.Owner)
-		urlMap.Set(constant.EnvironmentKey, rc.application.Environment)
+	if rc.applicationCompat != nil {
+		urlMap.Set(constant.ApplicationKey, rc.applicationCompat.Name)
+		urlMap.Set(constant.OrganizationKey, rc.applicationCompat.Organization)
+		urlMap.Set(constant.NameKey, rc.applicationCompat.Name)
+		urlMap.Set(constant.ModuleKey, rc.applicationCompat.Module)
+		urlMap.Set(constant.AppVersionKey, rc.applicationCompat.Version)
+		urlMap.Set(constant.OwnerKey, rc.applicationCompat.Owner)
+		urlMap.Set(constant.EnvironmentKey, rc.applicationCompat.Environment)
 	}
 
 	// filter
diff --git a/common/config/application.go b/common/config/application.go
index 246346b..eaebd65 100644
--- a/common/config/application.go
+++ b/common/config/application.go
@@ -17,15 +17,7 @@
 
 package config
 
-import (
-	"github.com/creasty/defaults"
-
-	"github.com/pkg/errors"
-)
-
-import (
-	"dubbo.apache.org/dubbo-go/v3/common/constant"
-)
+// todo(DMwangnima): think about the location of this type of configuration.
 
 // ApplicationConfig is a configuration for current applicationConfig, whether the applicationConfig is a provider or a consumer
 type ApplicationConfig struct {
@@ -41,29 +33,6 @@
 	Tag          string `yaml:"tag" json:"tag,omitempty" property:"tag"`
 }
 
-// Prefix dubbo.application
-func (ac *ApplicationConfig) Prefix() string {
-	return constant.ApplicationConfigPrefix
-}
-
-// Init  application config and set default value
-func (ac *ApplicationConfig) Init() error {
-	if ac == nil {
-		return errors.New("application is null")
-	}
-	if err := ac.check(); err != nil {
-		return err
-	}
-	return nil
-}
-
-func (ac *ApplicationConfig) check() error {
-	if err := defaults.Set(ac); err != nil {
-		return err
-	}
-	return Verify(ac)
-}
-
 type ApplicationOption func(*ApplicationConfig)
 
 func WithOrganization(organization string) ApplicationOption {
diff --git a/config/application_config.go b/config/application_config.go
index 88a42c9..60ea32f 100644
--- a/config/application_config.go
+++ b/config/application_config.go
@@ -18,15 +18,58 @@
 package config
 
 import (
-	commonCfg "dubbo.apache.org/dubbo-go/v3/common/config"
+	"github.com/creasty/defaults"
+
+	"github.com/pkg/errors"
 )
 
+import (
+	"dubbo.apache.org/dubbo-go/v3/common/constant"
+)
+
+// ApplicationConfig is a configuration for current applicationConfig, whether the applicationConfig is a provider or a consumer
+type ApplicationConfig struct {
+	Organization string `default:"dubbo-go" yaml:"organization" json:"organization,omitempty" property:"organization"`
+	Name         string `default:"dubbo.io" yaml:"name" json:"name,omitempty" property:"name"`
+	Module       string `default:"sample" yaml:"module" json:"module,omitempty" property:"module"`
+	Group        string `yaml:"group" json:"group,omitempty" property:"module"`
+	Version      string `yaml:"version" json:"version,omitempty" property:"version"`
+	Owner        string `default:"dubbo-go" yaml:"owner" json:"owner,omitempty" property:"owner"`
+	Environment  string `yaml:"environment" json:"environment,omitempty" property:"environment"`
+	// the metadata type. remote or local
+	MetadataType string `default:"local" yaml:"metadata-type" json:"metadataType,omitempty" property:"metadataType"`
+	Tag          string `yaml:"tag" json:"tag,omitempty" property:"tag"`
+}
+
+// Prefix dubbo.application
+func (ac *ApplicationConfig) Prefix() string {
+	return constant.ApplicationConfigPrefix
+}
+
+// Init  application config and set default value
+func (ac *ApplicationConfig) Init() error {
+	if ac == nil {
+		return errors.New("application is null")
+	}
+	if err := ac.check(); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (ac *ApplicationConfig) check() error {
+	if err := defaults.Set(ac); err != nil {
+		return err
+	}
+	return verify(ac)
+}
+
 func NewApplicationConfigBuilder() *ApplicationConfigBuilder {
-	return &ApplicationConfigBuilder{application: &commonCfg.ApplicationConfig{}}
+	return &ApplicationConfigBuilder{application: &ApplicationConfig{}}
 }
 
 type ApplicationConfigBuilder struct {
-	application *commonCfg.ApplicationConfig
+	application *ApplicationConfig
 }
 
 func (acb *ApplicationConfigBuilder) SetOrganization(organization string) *ApplicationConfigBuilder {
@@ -64,6 +107,6 @@
 	return acb
 }
 
-func (acb *ApplicationConfigBuilder) Build() *commonCfg.ApplicationConfig {
+func (acb *ApplicationConfigBuilder) Build() *ApplicationConfig {
 	return acb.application
 }
diff --git a/config/consumer_config.go b/config/consumer_config.go
index fbcf5f3..c49811f 100644
--- a/config/consumer_config.go
+++ b/config/consumer_config.go
@@ -32,7 +32,6 @@
 )
 
 import (
-	"dubbo.apache.org/dubbo-go/v3/client"
 	"dubbo.apache.org/dubbo-go/v3/common"
 	"dubbo.apache.org/dubbo-go/v3/common/constant"
 )
@@ -43,21 +42,19 @@
 
 // ConsumerConfig is Consumer default configuration
 type ConsumerConfig struct {
-	Filter                         string                             `yaml:"filter" json:"filter,omitempty" property:"filter"`
-	RegistryIDs                    []string                           `yaml:"registry-ids" json:"registry-ids,omitempty" property:"registry-ids"`
-	Protocol                       string                             `yaml:"protocol" json:"protocol,omitempty" property:"protocol"`
-	RequestTimeout                 string                             `default:"3s" yaml:"request-timeout" json:"request-timeout,omitempty" property:"request-timeout"`
-	ProxyFactory                   string                             `default:"default" yaml:"proxy" json:"proxy,omitempty" property:"proxy"`
-	Check                          bool                               `yaml:"check" json:"check,omitempty" property:"check"`
-	AdaptiveService                bool                               `default:"false" yaml:"adaptive-service" json:"adaptive-service" property:"adaptive-service"`
-	References                     map[string]*client.ReferenceConfig `yaml:"references" json:"references,omitempty" property:"references"`
-	TracingKey                     string                             `yaml:"tracing-key" json:"tracing-key" property:"tracing-key"`
-	FilterConf                     interface{}                        `yaml:"filter-conf" json:"filter-conf,omitempty" property:"filter-conf"`
-	MaxWaitTimeForServiceDiscovery string                             `default:"3s" yaml:"max-wait-time-for-service-discovery" json:"max-wait-time-for-service-discovery,omitempty" property:"max-wait-time-for-service-discovery"`
-	MeshEnabled                    bool                               `yaml:"mesh-enabled" json:"mesh-enabled,omitempty" property:"mesh-enabled"`
+	Filter                         string                      `yaml:"filter" json:"filter,omitempty" property:"filter"`
+	RegistryIDs                    []string                    `yaml:"registry-ids" json:"registry-ids,omitempty" property:"registry-ids"`
+	Protocol                       string                      `yaml:"protocol" json:"protocol,omitempty" property:"protocol"`
+	RequestTimeout                 string                      `default:"3s" yaml:"request-timeout" json:"request-timeout,omitempty" property:"request-timeout"`
+	ProxyFactory                   string                      `default:"default" yaml:"proxy" json:"proxy,omitempty" property:"proxy"`
+	Check                          bool                        `yaml:"check" json:"check,omitempty" property:"check"`
+	AdaptiveService                bool                        `default:"false" yaml:"adaptive-service" json:"adaptive-service" property:"adaptive-service"`
+	References                     map[string]*ReferenceConfig `yaml:"references" json:"references,omitempty" property:"references"`
+	TracingKey                     string                      `yaml:"tracing-key" json:"tracing-key" property:"tracing-key"`
+	FilterConf                     interface{}                 `yaml:"filter-conf" json:"filter-conf,omitempty" property:"filter-conf"`
+	MaxWaitTimeForServiceDiscovery string                      `default:"3s" yaml:"max-wait-time-for-service-discovery" json:"max-wait-time-for-service-discovery,omitempty" property:"max-wait-time-for-service-discovery"`
+	MeshEnabled                    bool                        `yaml:"mesh-enabled" json:"mesh-enabled,omitempty" property:"mesh-enabled"`
 	rootConfig                     *RootConfig
-
-	refOpts []client.ReferenceOption
 }
 
 // Prefix dubbo.consumer
@@ -92,20 +89,6 @@
 			break
 		}
 	}
-
-	cc.refOpts = []client.ReferenceOption{
-		client.WithFilter(cc.Filter),
-		client.WithRegistryIDs(cc.RegistryIDs),
-		client.WithProtocol(cc.Protocol),
-		client.WithTracingKey(cc.TracingKey),
-		client.WithCheck(cc.Check),
-		client.WithMeshEnabled(cc.MeshEnabled),
-		client.WithAdaptiveService(cc.AdaptiveService),
-		client.WithProxyFactory(cc.ProxyFactory),
-		client.WithApplication(rc.Application),
-		client.WithRegistries(rc.Registries),
-	}
-
 	for key, referenceConfig := range cc.References {
 		if referenceConfig.InterfaceName == "" {
 			reference := GetConsumerService(key)
@@ -122,11 +105,10 @@
 				referenceConfig.InterfaceName = triplePBService.XXX_InterfaceName()
 			}
 		}
-		if err := referenceConfig.Init(cc.refOpts...); err != nil {
+		if err := referenceConfig.Init(rc); err != nil {
 			return err
 		}
 	}
-	// todo: maybe defaults.Set function should be moved to upper place?
 	if err := defaults.Set(cc); err != nil {
 		return err
 	}
@@ -155,24 +137,14 @@
 				// use interface name defined by pb
 				refConfig.InterfaceName = triplePBService.XXX_InterfaceName()
 			}
-			if err := refConfig.Init(cc.refOpts...); err != nil {
+			if err := refConfig.Init(rootConfig); err != nil {
 				logger.Errorf(fmt.Sprintf("reference with registeredTypeName = %s init failed! err: %#v", registeredTypeName, err))
 				continue
 			}
 		}
+		refConfig.id = registeredTypeName
 		refConfig.Refer(refRPCService)
 		refConfig.Implement(refRPCService)
-		SetConsumerServiceByInterfaceName(refConfig.InterfaceName, refRPCService)
-	}
-
-	for info, refRPCService := range GetClientInfoServicesMap() {
-		refConfig, ok := cc.References[info.InterfaceName]
-		if !ok {
-			logger.Errorf("Dubbo-go can not find %s Reference in References config, please check your configuration file", info.InterfaceName)
-			continue
-		}
-		refConfig.ReferWithInfo(info)
-		refConfig.Implement(refRPCService)
 	}
 
 	var maxWait int
@@ -193,7 +165,7 @@
 				(ref.Check == nil && cc.Check && GetProviderService(key) == nil) ||
 				(ref.Check == nil && GetProviderService(key) == nil) { // default to true
 
-				if !ref.CheckAvailable() {
+				if ref.invoker != nil && !ref.invoker.IsAvailable() {
 					checkok = false
 					count++
 					if count > maxWait {
@@ -204,6 +176,9 @@
 					time.Sleep(time.Second * 1)
 					break
 				}
+				if ref.invoker == nil {
+					logger.Warnf("The interface %s invoker not exist, may you should check your interface config.", ref.InterfaceName)
+				}
 			}
 		}
 		if checkok {
@@ -219,7 +194,7 @@
 
 func newEmptyConsumerConfig() *ConsumerConfig {
 	newConsumerConfig := &ConsumerConfig{
-		References:     make(map[string]*client.ReferenceConfig, 8),
+		References:     make(map[string]*ReferenceConfig, 8),
 		RequestTimeout: "3s",
 		Check:          true,
 	}
@@ -264,12 +239,12 @@
 	return ccb
 }
 
-func (ccb *ConsumerConfigBuilder) AddReference(referenceKey string, referenceConfig *client.ReferenceConfig) *ConsumerConfigBuilder {
+func (ccb *ConsumerConfigBuilder) AddReference(referenceKey string, referenceConfig *ReferenceConfig) *ConsumerConfigBuilder {
 	ccb.consumerConfig.References[referenceKey] = referenceConfig
 	return ccb
 }
 
-func (ccb *ConsumerConfigBuilder) SetReferences(references map[string]*client.ReferenceConfig) *ConsumerConfigBuilder {
+func (ccb *ConsumerConfigBuilder) SetReferences(references map[string]*ReferenceConfig) *ConsumerConfigBuilder {
 	ccb.consumerConfig.References = references
 	return ccb
 }
diff --git a/config/reference_config.go b/config/reference_config.go
index 824f315..1d6899e 100644
--- a/config/reference_config.go
+++ b/config/reference_config.go
@@ -18,20 +18,390 @@
 package config
 
 import (
-	"dubbo.apache.org/dubbo-go/v3/client"
+	"fmt"
+	"net/url"
+	"os"
+	"strconv"
+	"time"
 )
 
+import (
+	"github.com/creasty/defaults"
+
+	"github.com/dubbogo/gost/log/logger"
+	gxstrings "github.com/dubbogo/gost/strings"
+
+	constant2 "github.com/dubbogo/triple/pkg/common/constant"
+)
+
+import (
+	"dubbo.apache.org/dubbo-go/v3/cluster/directory/static"
+	"dubbo.apache.org/dubbo-go/v3/common"
+	"dubbo.apache.org/dubbo-go/v3/common/constant"
+	"dubbo.apache.org/dubbo-go/v3/common/extension"
+	"dubbo.apache.org/dubbo-go/v3/config/generic"
+	"dubbo.apache.org/dubbo-go/v3/protocol"
+	"dubbo.apache.org/dubbo-go/v3/protocol/protocolwrapper"
+	"dubbo.apache.org/dubbo-go/v3/proxy"
+)
+
+// ReferenceConfig is the configuration of service consumer
+type ReferenceConfig struct {
+	pxy              *proxy.Proxy
+	id               string
+	InterfaceName    string            `yaml:"interface"  json:"interface,omitempty" property:"interface"`
+	Check            *bool             `yaml:"check"  json:"check,omitempty" property:"check"`
+	URL              string            `yaml:"url"  json:"url,omitempty" property:"url"`
+	Filter           string            `yaml:"filter" json:"filter,omitempty" property:"filter"`
+	Protocol         string            `yaml:"protocol"  json:"protocol,omitempty" property:"protocol"`
+	RegistryIDs      []string          `yaml:"registry-ids"  json:"registry-ids,omitempty"  property:"registry-ids"`
+	Cluster          string            `yaml:"cluster"  json:"cluster,omitempty" property:"cluster"`
+	Loadbalance      string            `yaml:"loadbalance"  json:"loadbalance,omitempty" property:"loadbalance"`
+	Retries          string            `yaml:"retries"  json:"retries,omitempty" property:"retries"`
+	Group            string            `yaml:"group"  json:"group,omitempty" property:"group"`
+	Version          string            `yaml:"version"  json:"version,omitempty" property:"version"`
+	Serialization    string            `yaml:"serialization" json:"serialization" property:"serialization"`
+	ProvidedBy       string            `yaml:"provided_by"  json:"provided_by,omitempty" property:"provided_by"`
+	Methods          []*MethodConfig   `yaml:"methods"  json:"methods,omitempty" property:"methods"`
+	Async            bool              `yaml:"async"  json:"async,omitempty" property:"async"`
+	Params           map[string]string `yaml:"params"  json:"params,omitempty" property:"params"`
+	invoker          protocol.Invoker
+	urls             []*common.URL
+	Generic          string `yaml:"generic"  json:"generic,omitempty" property:"generic"`
+	Sticky           bool   `yaml:"sticky"   json:"sticky,omitempty" property:"sticky"`
+	RequestTimeout   string `yaml:"timeout"  json:"timeout,omitempty" property:"timeout"`
+	ForceTag         bool   `yaml:"force.tag"  json:"force.tag,omitempty" property:"force.tag"`
+	TracingKey       string `yaml:"tracing-key" json:"tracing-key,omitempty" propertiy:"tracing-key"`
+	rootConfig       *RootConfig
+	metaDataType     string
+	MeshProviderPort int `yaml:"mesh-provider-port" json:"mesh-provider-port,omitempty" propertiy:"mesh-provider-port"`
+}
+
+func (rc *ReferenceConfig) Prefix() string {
+	return constant.ReferenceConfigPrefix + rc.InterfaceName + "."
+}
+
+func (rc *ReferenceConfig) Init(root *RootConfig) error {
+	for _, method := range rc.Methods {
+		if err := method.Init(); err != nil {
+			return err
+		}
+	}
+	if err := defaults.Set(rc); err != nil {
+		return err
+	}
+	rc.rootConfig = root
+	if root.Application != nil {
+		rc.metaDataType = root.Application.MetadataType
+		if rc.Group == "" {
+			rc.Group = root.Application.Group
+		}
+		if rc.Version == "" {
+			rc.Version = root.Application.Version
+		}
+	}
+	if rc.Filter == "" {
+		rc.Filter = root.Consumer.Filter
+	}
+	if rc.Cluster == "" {
+		rc.Cluster = "failover"
+	}
+	rc.RegistryIDs = translateIds(rc.RegistryIDs)
+	if len(rc.RegistryIDs) <= 0 {
+		rc.RegistryIDs = root.Consumer.RegistryIDs
+	}
+
+	if rc.Protocol == "" {
+		rc.Protocol = root.Consumer.Protocol
+	}
+
+	if rc.TracingKey == "" {
+		rc.TracingKey = root.Consumer.TracingKey
+	}
+	if rc.Check == nil {
+		rc.Check = &root.Consumer.Check
+	}
+	return verify(rc)
+}
+
+func getEnv(key, fallback string) string {
+	if value, ok := os.LookupEnv(key); ok {
+		return value
+	}
+	return fallback
+}
+
+func updateOrCreateMeshURL(rc *ReferenceConfig) {
+	if rc.URL != "" {
+		logger.Infof("URL specified explicitly %v", rc.URL)
+	}
+
+	if !rc.rootConfig.Consumer.MeshEnabled {
+		return
+	}
+	if rc.Protocol != constant2.TRIPLE {
+		panic(fmt.Sprintf("Mesh mode enabled, Triple protocol expected but %v protocol found!", rc.Protocol))
+	}
+	if rc.ProvidedBy == "" {
+		panic("Mesh mode enabled, provided-by should not be empty!")
+	}
+
+	podNamespace := getEnv(constant.PodNamespaceEnvKey, constant.DefaultNamespace)
+	clusterDomain := getEnv(constant.ClusterDomainKey, constant.DefaultClusterDomain)
+
+	var meshPort int
+	if rc.MeshProviderPort > 0 {
+		meshPort = rc.MeshProviderPort
+	} else {
+		meshPort = constant.DefaultMeshPort
+	}
+
+	rc.URL = "tri://" + rc.ProvidedBy + "." + podNamespace + constant.SVC + clusterDomain + ":" + strconv.Itoa(meshPort)
+}
+
+// Refer retrieves invokers from urls.
+func (rc *ReferenceConfig) Refer(srv interface{}) {
+	// If adaptive service is enabled,
+	// the cluster and load balance should be overridden to "adaptivesvc" and "p2c" respectively.
+	if rc.rootConfig.Consumer.AdaptiveService {
+		rc.Cluster = constant.ClusterKeyAdaptiveService
+		rc.Loadbalance = constant.LoadBalanceKeyP2C
+	}
+
+	// cfgURL is an interface-level invoker url, in the other words, it represents an interface.
+	cfgURL := common.NewURLWithOptions(
+		common.WithPath(rc.InterfaceName),
+		common.WithProtocol(rc.Protocol),
+		common.WithParams(rc.getURLMap()),
+		common.WithParamsValue(constant.BeanNameKey, rc.id),
+		common.WithParamsValue(constant.MetadataTypeKey, rc.metaDataType),
+	)
+
+	SetConsumerServiceByInterfaceName(rc.InterfaceName, srv)
+	if rc.ForceTag {
+		cfgURL.AddParam(constant.ForceUseTag, "true")
+	}
+	rc.postProcessConfig(cfgURL)
+
+	// if mesh-enabled is set
+	updateOrCreateMeshURL(rc)
+
+	// retrieving urls from config, and appending the urls to rc.urls
+	if rc.URL != "" { // use user-specific urls
+		/*
+			 Two types of URL are allowed for rc.URL:
+				1. direct url: server IP, that is, no need for a registry anymore
+				2. registry url
+			 They will be handled in different ways:
+			 For example, we have a direct url and a registry url:
+				1. "tri://localhost:10000" is a direct url
+				2. "registry://localhost:2181" is a registry url.
+			 Then, rc.URL looks like a string separated by semicolon: "tri://localhost:10000;registry://localhost:2181".
+			 The result of urlStrings is a string array: []string{"tri://localhost:10000", "registry://localhost:2181"}.
+		*/
+		urlStrings := gxstrings.RegSplit(rc.URL, "\\s*[;]+\\s*")
+		for _, urlStr := range urlStrings {
+			serviceURL, err := common.NewURL(urlStr)
+			if err != nil {
+				panic(fmt.Sprintf("url configuration error,  please check your configuration, user specified URL %v refer error, error message is %v ", urlStr, err.Error()))
+			}
+			if serviceURL.Protocol == constant.RegistryProtocol { // serviceURL in this branch is a registry protocol
+				serviceURL.SubURL = cfgURL
+				rc.urls = append(rc.urls, serviceURL)
+			} else { // serviceURL in this branch is the target endpoint IP address
+				if serviceURL.Path == "" {
+					serviceURL.Path = "/" + rc.InterfaceName
+				}
+				// replace params of serviceURL with params of cfgUrl
+				// other stuff, e.g. IP, port, etc., are same as serviceURL
+				newURL := common.MergeURL(serviceURL, cfgURL)
+				newURL.AddParam("peer", "true")
+				rc.urls = append(rc.urls, newURL)
+			}
+		}
+	} else { // use registry configs
+		rc.urls = LoadRegistries(rc.RegistryIDs, rc.rootConfig.Registries, common.CONSUMER)
+		// set url to regURLs
+		for _, regURL := range rc.urls {
+			regURL.SubURL = cfgURL
+		}
+	}
+
+	// Get invokers according to rc.urls
+	var (
+		invoker protocol.Invoker
+		regURL  *common.URL
+	)
+	invokers := make([]protocol.Invoker, len(rc.urls))
+	for i, u := range rc.urls {
+		if u.Protocol == constant.ServiceRegistryProtocol {
+			invoker = extension.GetProtocol(constant.RegistryProtocol).Refer(u)
+		} else {
+			invoker = extension.GetProtocol(u.Protocol).Refer(u)
+		}
+
+		if rc.URL != "" {
+			invoker = protocolwrapper.BuildInvokerChain(invoker, constant.ReferenceFilterKey)
+		}
+
+		invokers[i] = invoker
+		if u.Protocol == constant.RegistryProtocol {
+			regURL = u
+		}
+	}
+
+	// TODO(hxmhlt): decouple from directory, config should not depend on directory module
+	if len(invokers) == 1 {
+		rc.invoker = invokers[0]
+		if rc.URL != "" {
+			hitClu := constant.ClusterKeyFailover
+			if u := rc.invoker.GetURL(); u != nil {
+				hitClu = u.GetParam(constant.ClusterKey, constant.ClusterKeyZoneAware)
+			}
+			cluster, err := extension.GetCluster(hitClu)
+			if err != nil {
+				panic(err)
+			} else {
+				rc.invoker = cluster.Join(static.NewDirectory(invokers))
+			}
+		}
+	} else {
+		var hitClu string
+		if regURL != nil {
+			// for multi-subscription scenario, use 'zone-aware' policy by default
+			hitClu = constant.ClusterKeyZoneAware
+		} else {
+			// not a registry url, must be direct invoke.
+			hitClu = constant.ClusterKeyFailover
+			if u := invokers[0].GetURL(); u != nil {
+				hitClu = u.GetParam(constant.ClusterKey, constant.ClusterKeyZoneAware)
+			}
+		}
+		cluster, err := extension.GetCluster(hitClu)
+		if err != nil {
+			panic(err)
+		} else {
+			rc.invoker = cluster.Join(static.NewDirectory(invokers))
+		}
+	}
+
+	// publish consumer's metadata
+	publishServiceDefinition(cfgURL)
+	// create proxy
+	if rc.Async {
+		callback := GetCallback(rc.id)
+		rc.pxy = extension.GetProxyFactory(rc.rootConfig.Consumer.ProxyFactory).GetAsyncProxy(rc.invoker, callback, cfgURL)
+	} else {
+		rc.pxy = extension.GetProxyFactory(rc.rootConfig.Consumer.ProxyFactory).GetProxy(rc.invoker, cfgURL)
+	}
+}
+
+// Implement
+// @v is service provider implemented RPCService
+func (rc *ReferenceConfig) Implement(v common.RPCService) {
+	rc.pxy.Implement(v)
+}
+
+// GetRPCService gets RPCService from proxy
+func (rc *ReferenceConfig) GetRPCService() common.RPCService {
+	return rc.pxy.Get()
+}
+
+// GetProxy gets proxy
+func (rc *ReferenceConfig) GetProxy() *proxy.Proxy {
+	return rc.pxy
+}
+
+func (rc *ReferenceConfig) getURLMap() url.Values {
+	urlMap := url.Values{}
+	// first set user params
+	for k, v := range rc.Params {
+		urlMap.Set(k, v)
+	}
+	urlMap.Set(constant.InterfaceKey, rc.InterfaceName)
+	urlMap.Set(constant.TimestampKey, strconv.FormatInt(time.Now().Unix(), 10))
+	urlMap.Set(constant.ClusterKey, rc.Cluster)
+	urlMap.Set(constant.LoadbalanceKey, rc.Loadbalance)
+	urlMap.Set(constant.RetriesKey, rc.Retries)
+	urlMap.Set(constant.GroupKey, rc.Group)
+	urlMap.Set(constant.VersionKey, rc.Version)
+	urlMap.Set(constant.GenericKey, rc.Generic)
+	urlMap.Set(constant.RegistryRoleKey, strconv.Itoa(common.CONSUMER))
+	urlMap.Set(constant.ProvidedBy, rc.ProvidedBy)
+	urlMap.Set(constant.SerializationKey, rc.Serialization)
+	urlMap.Set(constant.TracingConfigKey, rc.TracingKey)
+
+	urlMap.Set(constant.ReleaseKey, "dubbo-golang-"+constant.Version)
+	urlMap.Set(constant.SideKey, (common.RoleType(common.CONSUMER)).Role())
+
+	if len(rc.RequestTimeout) != 0 {
+		urlMap.Set(constant.TimeoutKey, rc.RequestTimeout)
+	}
+	// getty invoke async or sync
+	urlMap.Set(constant.AsyncKey, strconv.FormatBool(rc.Async))
+	urlMap.Set(constant.StickyKey, strconv.FormatBool(rc.Sticky))
+
+	// applicationConfig info
+	urlMap.Set(constant.ApplicationKey, rc.rootConfig.Application.Name)
+	urlMap.Set(constant.OrganizationKey, rc.rootConfig.Application.Organization)
+	urlMap.Set(constant.NameKey, rc.rootConfig.Application.Name)
+	urlMap.Set(constant.ModuleKey, rc.rootConfig.Application.Module)
+	urlMap.Set(constant.AppVersionKey, rc.rootConfig.Application.Version)
+	urlMap.Set(constant.OwnerKey, rc.rootConfig.Application.Owner)
+	urlMap.Set(constant.EnvironmentKey, rc.rootConfig.Application.Environment)
+
+	// filter
+	defaultReferenceFilter := constant.DefaultReferenceFilters
+	if rc.Generic != "" {
+		defaultReferenceFilter = constant.GenericFilterKey + "," + defaultReferenceFilter
+	}
+	urlMap.Set(constant.ReferenceFilterKey, mergeValue(rc.Filter, "", defaultReferenceFilter))
+
+	for _, v := range rc.Methods {
+		urlMap.Set("methods."+v.Name+"."+constant.LoadbalanceKey, v.LoadBalance)
+		urlMap.Set("methods."+v.Name+"."+constant.RetriesKey, v.Retries)
+		urlMap.Set("methods."+v.Name+"."+constant.StickyKey, strconv.FormatBool(v.Sticky))
+		if len(v.RequestTimeout) != 0 {
+			urlMap.Set("methods."+v.Name+"."+constant.TimeoutKey, v.RequestTimeout)
+		}
+	}
+
+	return urlMap
+}
+
+// GenericLoad ...
+func (rc *ReferenceConfig) GenericLoad(id string) {
+	genericService := generic.NewGenericService(rc.id)
+	SetConsumerService(genericService)
+	rc.id = id
+	rc.Refer(genericService)
+	rc.Implement(genericService)
+}
+
+// GetInvoker get invoker from ReferenceConfig
+func (rc *ReferenceConfig) GetInvoker() protocol.Invoker {
+	return rc.invoker
+}
+
+// postProcessConfig asks registered ConfigPostProcessor to post-process the current ReferenceConfig.
+func (rc *ReferenceConfig) postProcessConfig(url *common.URL) {
+	for _, p := range extension.GetConfigPostProcessors() {
+		p.PostProcessReferenceConfig(url)
+	}
+}
+
 //////////////////////////////////// reference config api
+
 // newEmptyReferenceConfig returns empty ReferenceConfig
-func newEmptyReferenceConfig() *client.ReferenceConfig {
-	newReferenceConfig := &client.ReferenceConfig{}
-	newReferenceConfig.Methods = make([]*client.MethodConfig, 0, 8)
+func newEmptyReferenceConfig() *ReferenceConfig {
+	newReferenceConfig := &ReferenceConfig{}
+	newReferenceConfig.Methods = make([]*MethodConfig, 0, 8)
 	newReferenceConfig.Params = make(map[string]string, 8)
 	return newReferenceConfig
 }
 
 type ReferenceConfigBuilder struct {
-	referenceConfig *client.ReferenceConfig
+	referenceConfig *ReferenceConfig
 }
 
 func NewReferenceConfigBuilder() *ReferenceConfigBuilder {
@@ -107,13 +477,13 @@
 	return pcb
 }
 
-func (pcb *ReferenceConfigBuilder) SetMethodConfig(methodConfigs []*client.MethodConfig) *ReferenceConfigBuilder {
+func (pcb *ReferenceConfigBuilder) SetMethodConfig(methodConfigs []*MethodConfig) *ReferenceConfigBuilder {
 	pcb.referenceConfig.Methods = methodConfigs
 	return pcb
 }
 
-func (pcb *ReferenceConfigBuilder) AddMethodConfig(methodConfigs *client.MethodConfig) *ReferenceConfigBuilder {
-	pcb.referenceConfig.Methods = append(pcb.referenceConfig.Methods, methodConfigs)
+func (pcb *ReferenceConfigBuilder) AddMethodConfig(methodConfig *MethodConfig) *ReferenceConfigBuilder {
+	pcb.referenceConfig.Methods = append(pcb.referenceConfig.Methods, methodConfig)
 	return pcb
 }
 
@@ -147,6 +517,6 @@
 	return pcb
 }
 
-func (pcb *ReferenceConfigBuilder) Build() *client.ReferenceConfig {
+func (pcb *ReferenceConfigBuilder) Build() *ReferenceConfig {
 	return pcb.referenceConfig
 }
diff --git a/config/registry_config.go b/config/registry_config.go
index 2f196fe..9eca5ea 100644
--- a/config/registry_config.go
+++ b/config/registry_config.go
@@ -18,44 +18,281 @@
 package config
 
 import (
+	"net/url"
+	"strconv"
+	"strings"
+)
+
+import (
+	"github.com/creasty/defaults"
+
+	"github.com/dubbogo/gost/log/logger"
+
+	perrors "github.com/pkg/errors"
+)
+
+import (
+	"dubbo.apache.org/dubbo-go/v3/common"
+	"dubbo.apache.org/dubbo-go/v3/common/constant"
+	"dubbo.apache.org/dubbo-go/v3/common/extension"
+	"dubbo.apache.org/dubbo-go/v3/config/instance"
 	"dubbo.apache.org/dubbo-go/v3/registry"
 )
 
+// RegistryConfig is the configuration of the registry center
+type RegistryConfig struct {
+	Protocol          string            `validate:"required" yaml:"protocol"  json:"protocol,omitempty" property:"protocol"`
+	Timeout           string            `default:"5s" validate:"required" yaml:"timeout" json:"timeout,omitempty" property:"timeout"` // unit: second
+	Group             string            `yaml:"group" json:"group,omitempty" property:"group"`
+	Namespace         string            `yaml:"namespace" json:"namespace,omitempty" property:"namespace"`
+	TTL               string            `default:"15m" yaml:"ttl" json:"ttl,omitempty" property:"ttl"` // unit: minute
+	Address           string            `validate:"required" yaml:"address" json:"address,omitempty" property:"address"`
+	Username          string            `yaml:"username" json:"username,omitempty" property:"username"`
+	Password          string            `yaml:"password" json:"password,omitempty"  property:"password"`
+	Simplified        bool              `yaml:"simplified" json:"simplified,omitempty"  property:"simplified"`
+	Preferred         bool              `yaml:"preferred" json:"preferred,omitempty" property:"preferred"` // Always use this registry first if set to true, useful when subscribe to multiple registriesConfig
+	Zone              string            `yaml:"zone" json:"zone,omitempty" property:"zone"`                // The region where the registry belongs, usually used to isolate traffics
+	Weight            int64             `yaml:"weight" json:"weight,omitempty" property:"weight"`          // Affects traffic distribution among registriesConfig, useful when subscribe to multiple registriesConfig Take effect only when no preferred registry is specified.
+	Params            map[string]string `yaml:"params" json:"params,omitempty" property:"params"`
+	RegistryType      string            `yaml:"registry-type"`
+	UseAsMetaReport   bool              `default:"true" yaml:"use-as-meta-report" json:"use-as-meta-report,omitempty" property:"use-as-meta-report"`
+	UseAsConfigCenter bool              `default:"true" yaml:"use-as-config-center" json:"use-as-config-center,omitempty" property:"use-as-config-center"`
+}
+
+// Prefix dubbo.registries
+func (RegistryConfig) Prefix() string {
+	return constant.RegistryConfigPrefix
+}
+
+func (c *RegistryConfig) Init() error {
+	if err := defaults.Set(c); err != nil {
+		return err
+	}
+	return c.startRegistryConfig()
+}
+
+func (c *RegistryConfig) getUrlMap(roleType common.RoleType) url.Values {
+	urlMap := url.Values{}
+	urlMap.Set(constant.RegistryGroupKey, c.Group)
+	urlMap.Set(constant.RegistryRoleKey, strconv.Itoa(int(roleType)))
+	urlMap.Set(constant.RegistryKey, c.Protocol)
+	urlMap.Set(constant.RegistryTimeoutKey, c.Timeout)
+	// multi registry invoker weight label for load balance
+	urlMap.Set(constant.RegistryKey+"."+constant.RegistryLabelKey, strconv.FormatBool(true))
+	urlMap.Set(constant.RegistryKey+"."+constant.PreferredKey, strconv.FormatBool(c.Preferred))
+	urlMap.Set(constant.RegistryKey+"."+constant.RegistryZoneKey, c.Zone)
+	urlMap.Set(constant.RegistryKey+"."+constant.WeightKey, strconv.FormatInt(c.Weight, 10))
+	urlMap.Set(constant.RegistryTTLKey, c.TTL)
+	urlMap.Set(constant.ClientNameKey, clientNameID(c, c.Protocol, c.Address))
+
+	for k, v := range c.Params {
+		urlMap.Set(k, v)
+	}
+	return urlMap
+}
+
+func (c *RegistryConfig) startRegistryConfig() error {
+	c.translateRegistryAddress()
+	if c.UseAsMetaReport && isValid(c.Address) {
+		if tmpUrl, err := c.toMetadataReportUrl(); err == nil {
+			instance.SetMetadataReportInstanceByReg(tmpUrl)
+		} else {
+			return perrors.Wrap(err, "Start RegistryConfig failed.")
+		}
+	}
+	return verify(c)
+}
+
+// toMetadataReportUrl translate the registry configuration to the metadata reporting url
+func (c *RegistryConfig) toMetadataReportUrl() (*common.URL, error) {
+	res, err := common.NewURL(c.Address,
+		common.WithLocation(c.Address),
+		common.WithProtocol(c.Protocol),
+		common.WithUsername(c.Username),
+		common.WithPassword(c.Password),
+		common.WithParamsValue(constant.TimeoutKey, c.Timeout),
+		common.WithParamsValue(constant.ClientNameKey, clientNameID(c, c.Protocol, c.Address)),
+		common.WithParamsValue(constant.MetadataReportGroupKey, c.Group),
+		common.WithParamsValue(constant.MetadataReportNamespaceKey, c.Namespace),
+	)
+	if err != nil || len(res.Protocol) == 0 {
+		return nil, perrors.New("Invalid Registry Config.")
+	}
+	return res, nil
+}
+
+// translateRegistryAddress translate registry address
+//
+//	eg:address=nacos://127.0.0.1:8848 will return 127.0.0.1:8848 and protocol will set nacos
+func (c *RegistryConfig) translateRegistryAddress() string {
+	if strings.Contains(c.Address, "://") {
+		u, err := url.Parse(c.Address)
+		if err != nil {
+			logger.Errorf("The registry url is invalid, error: %#v", err)
+			panic(err)
+		}
+		c.Protocol = u.Scheme
+		c.Address = strings.Join([]string{u.Host, u.Path}, "")
+	}
+	return c.Address
+}
+
+func (c *RegistryConfig) GetInstance(roleType common.RoleType) (registry.Registry, error) {
+	u, err := c.toURL(roleType)
+	if err != nil {
+		return nil, err
+	}
+	// if the protocol == registry, set protocol the registry value in url.params
+	if u.Protocol == constant.RegistryProtocol {
+		u.Protocol = u.GetParam(constant.RegistryKey, "")
+	}
+	return extension.GetRegistry(u.Protocol, u)
+}
+
+func (c *RegistryConfig) toURL(roleType common.RoleType) (*common.URL, error) {
+	address := c.translateRegistryAddress()
+	var registryURLProtocol string
+	if c.RegistryType == constant.RegistryTypeService {
+		// service discovery protocol
+		registryURLProtocol = constant.ServiceRegistryProtocol
+	} else if c.RegistryType == constant.RegistryTypeInterface {
+		registryURLProtocol = constant.RegistryProtocol
+	} else {
+		registryURLProtocol = constant.ServiceRegistryProtocol
+	}
+	return common.NewURL(registryURLProtocol+"://"+address,
+		common.WithParams(c.getUrlMap(roleType)),
+		common.WithParamsValue(constant.RegistrySimplifiedKey, strconv.FormatBool(c.Simplified)),
+		common.WithParamsValue(constant.RegistryKey, c.Protocol),
+		common.WithParamsValue(constant.RegistryNamespaceKey, c.Namespace),
+		common.WithParamsValue(constant.RegistryTimeoutKey, c.Timeout),
+		common.WithUsername(c.Username),
+		common.WithPassword(c.Password),
+		common.WithLocation(c.Address),
+	)
+}
+
+func (c *RegistryConfig) toURLs(roleType common.RoleType) ([]*common.URL, error) {
+	address := c.translateRegistryAddress()
+	var urls []*common.URL
+	var err error
+	var registryURL *common.URL
+
+	if !isValid(c.Address) {
+		logger.Infof("Empty or N/A registry address found, the process will work with no registry enabled " +
+			"which means that the address of this instance will not be registered and not able to be found by other consumer instances.")
+		return urls, nil
+	}
+
+	if c.RegistryType == constant.RegistryTypeService {
+		// service discovery protocol
+		if registryURL, err = c.createNewURL(constant.ServiceRegistryProtocol, address, roleType); err == nil {
+			urls = append(urls, registryURL)
+		}
+	} else if c.RegistryType == constant.RegistryTypeInterface {
+		if registryURL, err = c.createNewURL(constant.RegistryProtocol, address, roleType); err == nil {
+			urls = append(urls, registryURL)
+		}
+	} else if c.RegistryType == constant.RegistryTypeAll {
+		if registryURL, err = c.createNewURL(constant.ServiceRegistryProtocol, address, roleType); err == nil {
+			urls = append(urls, registryURL)
+		}
+		if registryURL, err = c.createNewURL(constant.RegistryProtocol, address, roleType); err == nil {
+			urls = append(urls, registryURL)
+		}
+	} else {
+		if registryURL, err = c.createNewURL(constant.ServiceRegistryProtocol, address, roleType); err == nil {
+			urls = append(urls, registryURL)
+		}
+	}
+	return urls, err
+}
+
+func LoadRegistries(registryIds []string, registries map[string]*RegistryConfig, roleType common.RoleType) []*common.URL {
+	var registryURLs []*common.URL
+	//trSlice := strings.Split(targetRegistries, ",")
+
+	for k, registryConf := range registries {
+		target := false
+
+		// if user not config targetRegistries, default load all
+		// Notice: in func "func Split(s, sep string) []string" comment:
+		// if s does not contain sep and sep is not empty, SplitAfter returns
+		// a slice of length 1 whose only element is s. So we have to add the
+		// condition when targetRegistries string is not set (it will be "" when not set)
+		if len(registryIds) == 0 || (len(registryIds) == 1 && registryIds[0] == "") {
+			target = true
+		} else {
+			// else if user config targetRegistries
+			for _, tr := range registryIds {
+				if tr == k {
+					target = true
+					break
+				}
+			}
+		}
+
+		if target {
+			if urls, err := registryConf.toURLs(roleType); err != nil {
+				logger.Errorf("The registry id: %s url is invalid, error: %#v", k, err)
+				panic(err)
+			} else {
+				registryURLs = append(registryURLs, urls...)
+			}
+		}
+	}
+
+	return registryURLs
+}
+
+func (c *RegistryConfig) createNewURL(protocol string, address string, roleType common.RoleType) (*common.URL, error) {
+	return common.NewURL(protocol+"://"+address,
+		common.WithParams(c.getUrlMap(roleType)),
+		common.WithParamsValue(constant.RegistrySimplifiedKey, strconv.FormatBool(c.Simplified)),
+		common.WithParamsValue(constant.RegistryKey, c.Protocol),
+		common.WithParamsValue(constant.RegistryNamespaceKey, c.Namespace),
+		common.WithParamsValue(constant.RegistryTimeoutKey, c.Timeout),
+		common.WithUsername(c.Username),
+		common.WithPassword(c.Password),
+		common.WithLocation(c.Address),
+	)
+}
+
 const (
 	defaultZKAddr          = "127.0.0.1:2181" // default registry address of zookeeper
 	defaultNacosAddr       = "127.0.0.1:8848" // the default registry address of nacos
 	defaultRegistryTimeout = "3s"             // the default registry timeout
 )
 
-type RegistryConfigOpt func(config *registry.RegistryConfig) *registry.RegistryConfig
+type RegistryConfigOpt func(config *RegistryConfig) *RegistryConfig
 
 // NewRegistryConfigWithProtocolDefaultPort New default registry config
 // the input @protocol can only be:
 // "zookeeper" with default addr "127.0.0.1:2181"
 // "nacos" with default addr "127.0.0.1:8848"
-func NewRegistryConfigWithProtocolDefaultPort(protocol string) *registry.RegistryConfig {
+func NewRegistryConfigWithProtocolDefaultPort(protocol string) *RegistryConfig {
 	switch protocol {
 	case "zookeeper":
-		return &registry.RegistryConfig{
+		return &RegistryConfig{
 			Protocol: protocol,
 			Address:  defaultZKAddr,
 			Timeout:  defaultRegistryTimeout,
 		}
 	case "nacos":
-		return &registry.RegistryConfig{
+		return &RegistryConfig{
 			Protocol: protocol,
 			Address:  defaultNacosAddr,
 			Timeout:  defaultRegistryTimeout,
 		}
 	default:
-		return &registry.RegistryConfig{
+		return &RegistryConfig{
 			Protocol: protocol,
 		}
 	}
 }
 
-// NewRegistryConfig creates New registry.RegistryConfig with @opts
-func NewRegistryConfig(opts ...RegistryConfigOpt) *registry.RegistryConfig {
+// NewRegistryConfig creates New RegistryConfig with @opts
+func NewRegistryConfig(opts ...RegistryConfigOpt) *RegistryConfig {
 	newRegistryConfig := NewRegistryConfigWithProtocolDefaultPort("")
 	for _, v := range opts {
 		newRegistryConfig = v(newRegistryConfig)
@@ -65,7 +302,7 @@
 
 // WithRegistryProtocol returns RegistryConfigOpt with given @regProtocol name
 func WithRegistryProtocol(regProtocol string) RegistryConfigOpt {
-	return func(config *registry.RegistryConfig) *registry.RegistryConfig {
+	return func(config *RegistryConfig) *RegistryConfig {
 		config.Protocol = regProtocol
 		return config
 	}
@@ -73,7 +310,7 @@
 
 // WithRegistryAddress returns RegistryConfigOpt with given @addr registry address
 func WithRegistryAddress(addr string) RegistryConfigOpt {
-	return func(config *registry.RegistryConfig) *registry.RegistryConfig {
+	return func(config *RegistryConfig) *RegistryConfig {
 		config.Address = addr
 		return config
 	}
@@ -81,7 +318,7 @@
 
 // WithRegistryTimeOut returns RegistryConfigOpt with given @timeout registry config
 func WithRegistryTimeOut(timeout string) RegistryConfigOpt {
-	return func(config *registry.RegistryConfig) *registry.RegistryConfig {
+	return func(config *RegistryConfig) *RegistryConfig {
 		config.Timeout = timeout
 		return config
 	}
@@ -89,7 +326,7 @@
 
 // WithRegistryGroup returns RegistryConfigOpt with given @group registry group
 func WithRegistryGroup(group string) RegistryConfigOpt {
-	return func(config *registry.RegistryConfig) *registry.RegistryConfig {
+	return func(config *RegistryConfig) *RegistryConfig {
 		config.Group = group
 		return config
 	}
@@ -97,7 +334,7 @@
 
 // WithRegistryTTL returns RegistryConfigOpt with given @ttl registry ttl
 func WithRegistryTTL(ttl string) RegistryConfigOpt {
-	return func(config *registry.RegistryConfig) *registry.RegistryConfig {
+	return func(config *RegistryConfig) *RegistryConfig {
 		config.TTL = ttl
 		return config
 	}
@@ -105,7 +342,7 @@
 
 // WithRegistryUserName returns RegistryConfigOpt with given @userName registry userName
 func WithRegistryUserName(userName string) RegistryConfigOpt {
-	return func(config *registry.RegistryConfig) *registry.RegistryConfig {
+	return func(config *RegistryConfig) *RegistryConfig {
 		config.Username = userName
 		return config
 	}
@@ -113,7 +350,7 @@
 
 // WithRegistryPassword returns RegistryConfigOpt with given @psw registry password
 func WithRegistryPassword(psw string) RegistryConfigOpt {
-	return func(config *registry.RegistryConfig) *registry.RegistryConfig {
+	return func(config *RegistryConfig) *RegistryConfig {
 		config.Password = psw
 		return config
 	}
@@ -121,15 +358,15 @@
 
 // WithRegistrySimplified returns RegistryConfigOpt with given @simplified registry simplified flag
 func WithRegistrySimplified(simplified bool) RegistryConfigOpt {
-	return func(config *registry.RegistryConfig) *registry.RegistryConfig {
+	return func(config *RegistryConfig) *RegistryConfig {
 		config.Simplified = simplified
 		return config
 	}
 }
 
-// WithRegistryPreferred returns registry.RegistryConfig with given @preferred registry preferred flag
+// WithRegistryPreferred returns RegistryConfig with given @preferred registry preferred flag
 func WithRegistryPreferred(preferred bool) RegistryConfigOpt {
-	return func(config *registry.RegistryConfig) *registry.RegistryConfig {
+	return func(config *RegistryConfig) *RegistryConfig {
 		config.Preferred = preferred
 		return config
 	}
@@ -137,7 +374,7 @@
 
 // WithRegistryWeight returns RegistryConfigOpt with given @weight registry weight flag
 func WithRegistryWeight(weight int64) RegistryConfigOpt {
-	return func(config *registry.RegistryConfig) *registry.RegistryConfig {
+	return func(config *RegistryConfig) *RegistryConfig {
 		config.Weight = weight
 		return config
 	}
@@ -145,7 +382,7 @@
 
 // WithRegistryParams returns RegistryConfigOpt with given registry @params
 func WithRegistryParams(params map[string]string) RegistryConfigOpt {
-	return func(config *registry.RegistryConfig) *registry.RegistryConfig {
+	return func(config *RegistryConfig) *RegistryConfig {
 		config.Params = params
 		return config
 	}
@@ -153,12 +390,12 @@
 
 func NewRegistryConfigBuilder() *RegistryConfigBuilder {
 	return &RegistryConfigBuilder{
-		registryConfig: &registry.RegistryConfig{},
+		registryConfig: &RegistryConfig{},
 	}
 }
 
 type RegistryConfigBuilder struct {
-	registryConfig *registry.RegistryConfig
+	registryConfig *RegistryConfig
 }
 
 func (rcb *RegistryConfigBuilder) SetProtocol(protocol string) *RegistryConfigBuilder {
@@ -239,9 +476,18 @@
 	return rcb
 }
 
-func (rcb *RegistryConfigBuilder) Build() *registry.RegistryConfig {
+func (rcb *RegistryConfigBuilder) Build() *RegistryConfig {
 	if err := rcb.registryConfig.Init(); err != nil {
 		panic(err)
 	}
 	return rcb.registryConfig
 }
+
+// DynamicUpdateProperties update registry
+func (c *RegistryConfig) DynamicUpdateProperties(updateRegistryConfig *RegistryConfig) {
+	// if nacos's registry timeout not equal local root config's registry timeout , update.
+	if updateRegistryConfig != nil && updateRegistryConfig.Timeout != c.Timeout {
+		c.Timeout = updateRegistryConfig.Timeout
+		logger.Infof("RegistryConfigs Timeout was dynamically updated, new value:%v", c.Timeout)
+	}
+}
diff --git a/config/registry_config_test.go b/config/registry_config_test.go
index e4caa82..1223f6b 100644
--- a/config/registry_config_test.go
+++ b/config/registry_config_test.go
@@ -25,45 +25,109 @@
 	"github.com/stretchr/testify/assert"
 )
 
-// todo: think about how to expose functions of RegistryConfig
-//func TestNewRegistryConfigBuilder(t *testing.T) {
-//
-//	config := NewRegistryConfigBuilder().
-//		SetProtocol("nacos").
-//		SetTimeout("10s").
-//		SetGroup("group").
-//		SetNamespace("public").
-//		SetTTL("10s").
-//		SetAddress("127.0.0.1:8848").
-//		SetUsername("nacos").
-//		SetPassword("123456").
-//		SetSimplified(true).
-//		SetPreferred(true).
-//		SetZone("zone").
-//		SetWeight(100).
-//		SetParams(map[string]string{"timeout": "3s"}).
-//		AddParam("timeout", "15s").
-//		SetRegistryType("local").
-//		Build()
-//
-//	config.DynamicUpdateProperties(config)
-//
-//	assert.Equal(t, config.Prefix(), constant.RegistryConfigPrefix)
-//
-//	values := config.getUrlMap(common.PROVIDER)
-//	assert.Equal(t, values.Get("timeout"), "15s")
-//
-//	url, err := config.toMetadataReportUrl()
-//	assert.NoError(t, err)
-//	assert.Equal(t, url.GetParam("timeout", "3s"), "10s")
-//
-//	url, err = config.toURL(common.PROVIDER)
-//	assert.NoError(t, err)
-//	assert.Equal(t, url.GetParam("timeout", "3s"), "15s")
-//
-//	address := config.translateRegistryAddress()
-//	assert.Equal(t, address, "127.0.0.1:8848")
-//}
+import (
+	"dubbo.apache.org/dubbo-go/v3/common"
+	"dubbo.apache.org/dubbo-go/v3/common/constant"
+)
+
+func TestLoadRegistries(t *testing.T) {
+	target := []string{"shanghai1"}
+	regs := map[string]*RegistryConfig{
+
+		"shanghai1": {
+			Protocol: "mock",
+			Timeout:  "2s",
+			Group:    "shanghai_idc",
+			Address:  "127.0.0.2:2181,128.0.0.1:2181",
+			Username: "user1",
+			Password: "pwd1",
+		},
+	}
+	urls := LoadRegistries(target, regs, common.CONSUMER)
+	t.Logf("LoadRegistries() = urls:%v", urls)
+	assert.Equal(t, "127.0.0.2:2181,128.0.0.1:2181", urls[0].Location)
+}
+
+func TestLoadRegistries1(t *testing.T) {
+	target := []string{"shanghai1"}
+	regs := map[string]*RegistryConfig{
+
+		"shanghai1": {
+			Protocol: "mock",
+			Timeout:  "2s",
+			Group:    "shanghai_idc",
+			Address:  "127.0.0.2:2181",
+			Username: "user1",
+			Password: "pwd1",
+		},
+	}
+	urls := LoadRegistries(target, regs, common.CONSUMER)
+	t.Logf("LoadRegistries() = urls:%v", urls)
+	assert.Equal(t, "127.0.0.2:2181", urls[0].Location)
+}
+
+func TestRegistryTypeAll(t *testing.T) {
+	target := []string{"test"}
+	regs := map[string]*RegistryConfig{
+		"test": {
+			Protocol:     "mock",
+			Address:      "127.0.0.2:2181",
+			RegistryType: constant.RegistryTypeAll,
+		},
+	}
+	urls := LoadRegistries(target, regs, common.PROVIDER)
+	assert.Equal(t, 2, len(urls))
+}
+
+func TestTranslateRegistryAddress(t *testing.T) {
+	reg := new(RegistryConfig)
+	reg.Address = "nacos://127.0.0.1:8848"
+
+	reg.translateRegistryAddress()
+
+	assert.Equal(t, "nacos", reg.Protocol)
+	assert.Equal(t, "127.0.0.1:8848", reg.Address)
+}
+
+func TestNewRegistryConfigBuilder(t *testing.T) {
+
+	config := NewRegistryConfigBuilder().
+		SetProtocol("nacos").
+		SetTimeout("10s").
+		SetGroup("group").
+		SetNamespace("public").
+		SetTTL("10s").
+		SetAddress("127.0.0.1:8848").
+		SetUsername("nacos").
+		SetPassword("123456").
+		SetSimplified(true).
+		SetPreferred(true).
+		SetZone("zone").
+		SetWeight(100).
+		SetParams(map[string]string{"timeout": "3s"}).
+		AddParam("timeout", "15s").
+		SetRegistryType("local").
+		Build()
+
+	config.DynamicUpdateProperties(config)
+
+	assert.Equal(t, config.Prefix(), constant.RegistryConfigPrefix)
+
+	values := config.getUrlMap(common.PROVIDER)
+	assert.Equal(t, values.Get("timeout"), "15s")
+
+	url, err := config.toMetadataReportUrl()
+	assert.NoError(t, err)
+	assert.Equal(t, url.GetParam("timeout", "3s"), "10s")
+
+	url, err = config.toURL(common.PROVIDER)
+	assert.NoError(t, err)
+	assert.Equal(t, url.GetParam("timeout", "3s"), "15s")
+
+	address := config.translateRegistryAddress()
+	assert.Equal(t, address, "127.0.0.1:8848")
+}
+
 func TestNewRegistryConfig(t *testing.T) {
 	config := NewRegistryConfig(
 		WithRegistryProtocol("nacos"),
diff --git a/config/root_config.go b/config/root_config.go
index 95a1636..7517702 100644
--- a/config/root_config.go
+++ b/config/root_config.go
@@ -35,12 +35,10 @@
 
 import (
 	"dubbo.apache.org/dubbo-go/v3/common"
-	commonCfg "dubbo.apache.org/dubbo-go/v3/common/config"
 	"dubbo.apache.org/dubbo-go/v3/common/constant"
 	"dubbo.apache.org/dubbo-go/v3/common/extension"
 	"dubbo.apache.org/dubbo-go/v3/config_center"
 	"dubbo.apache.org/dubbo-go/v3/metadata/service/exporter"
-	"dubbo.apache.org/dubbo-go/v3/registry"
 )
 
 var (
@@ -50,23 +48,23 @@
 
 // RootConfig is the root config
 type RootConfig struct {
-	Application         *commonCfg.ApplicationConfig        `validate:"required" yaml:"application" json:"application,omitempty" property:"application"`
-	Protocols           map[string]*ProtocolConfig          `validate:"required" yaml:"protocols" json:"protocols" property:"protocols"`
-	Registries          map[string]*registry.RegistryConfig `yaml:"registries" json:"registries" property:"registries"`
-	ConfigCenter        *CenterConfig                       `yaml:"config-center" json:"config-center,omitempty"`
-	MetadataReport      *MetadataReportConfig               `yaml:"metadata-report" json:"metadata-report,omitempty" property:"metadata-report"`
-	Provider            *ProviderConfig                     `yaml:"provider" json:"provider" property:"provider"`
-	Consumer            *ConsumerConfig                     `yaml:"consumer" json:"consumer" property:"consumer"`
-	Metric              *MetricConfig                       `yaml:"metrics" json:"metrics,omitempty" property:"metrics"`
-	Tracing             map[string]*TracingConfig           `yaml:"tracing" json:"tracing,omitempty" property:"tracing"`
-	Logger              *LoggerConfig                       `yaml:"logger" json:"logger,omitempty" property:"logger"`
-	Shutdown            *ShutdownConfig                     `yaml:"shutdown" json:"shutdown,omitempty" property:"shutdown"`
-	Router              []*RouterConfig                     `yaml:"router" json:"router,omitempty" property:"router"`
-	EventDispatcherType string                              `default:"direct" yaml:"event-dispatcher-type" json:"event-dispatcher-type,omitempty"`
-	CacheFile           string                              `yaml:"cache_file" json:"cache_file,omitempty" property:"cache_file"`
-	Custom              *CustomConfig                       `yaml:"custom" json:"custom,omitempty" property:"custom"`
-	Profiles            *ProfilesConfig                     `yaml:"profiles" json:"profiles,omitempty" property:"profiles"`
-	TLSConfig           *TLSConfig                          `yaml:"tls_config" json:"tls_config,omitempty" property:"tls_config"`
+	Application         *ApplicationConfig         `validate:"required" yaml:"application" json:"application,omitempty" property:"application"`
+	Protocols           map[string]*ProtocolConfig `validate:"required" yaml:"protocols" json:"protocols" property:"protocols"`
+	Registries          map[string]*RegistryConfig `yaml:"registries" json:"registries" property:"registries"`
+	ConfigCenter        *CenterConfig              `yaml:"config-center" json:"config-center,omitempty"`
+	MetadataReport      *MetadataReportConfig      `yaml:"metadata-report" json:"metadata-report,omitempty" property:"metadata-report"`
+	Provider            *ProviderConfig            `yaml:"provider" json:"provider" property:"provider"`
+	Consumer            *ConsumerConfig            `yaml:"consumer" json:"consumer" property:"consumer"`
+	Metric              *MetricConfig              `yaml:"metrics" json:"metrics,omitempty" property:"metrics"`
+	Tracing             map[string]*TracingConfig  `yaml:"tracing" json:"tracing,omitempty" property:"tracing"`
+	Logger              *LoggerConfig              `yaml:"logger" json:"logger,omitempty" property:"logger"`
+	Shutdown            *ShutdownConfig            `yaml:"shutdown" json:"shutdown,omitempty" property:"shutdown"`
+	Router              []*RouterConfig            `yaml:"router" json:"router,omitempty" property:"router"`
+	EventDispatcherType string                     `default:"direct" yaml:"event-dispatcher-type" json:"event-dispatcher-type,omitempty"`
+	CacheFile           string                     `yaml:"cache_file" json:"cache_file,omitempty" property:"cache_file"`
+	Custom              *CustomConfig              `yaml:"custom" json:"custom,omitempty" property:"custom"`
+	Profiles            *ProfilesConfig            `yaml:"profiles" json:"profiles,omitempty" property:"profiles"`
+	TLSConfig           *TLSConfig                 `yaml:"tls_config" json:"tls_config,omitempty" property:"tls_config"`
 }
 
 func SetRootConfig(r RootConfig) {
@@ -96,7 +94,7 @@
 	return NewConsumerConfigBuilder().Build()
 }
 
-func GetApplicationConfig() *commonCfg.ApplicationConfig {
+func GetApplicationConfig() *ApplicationConfig {
 	return rootConfig.Application
 }
 
@@ -224,7 +222,7 @@
 		ConfigCenter:   NewConfigCenterConfigBuilder().Build(),
 		MetadataReport: NewMetadataReportConfigBuilder().Build(),
 		Application:    NewApplicationConfigBuilder().Build(),
-		Registries:     make(map[string]*registry.RegistryConfig),
+		Registries:     make(map[string]*RegistryConfig),
 		Protocols:      make(map[string]*ProtocolConfig),
 		Tracing:        make(map[string]*TracingConfig),
 		Provider:       NewProviderConfigBuilder().Build(),
@@ -246,7 +244,7 @@
 	rootConfig *RootConfig
 }
 
-func (rb *RootConfigBuilder) SetApplication(application *commonCfg.ApplicationConfig) *RootConfigBuilder {
+func (rb *RootConfigBuilder) SetApplication(application *ApplicationConfig) *RootConfigBuilder {
 	rb.rootConfig.Application = application
 	return rb
 }
@@ -256,7 +254,7 @@
 	return rb
 }
 
-func (rb *RootConfigBuilder) AddRegistry(registryID string, registryConfig *registry.RegistryConfig) *RootConfigBuilder {
+func (rb *RootConfigBuilder) AddRegistry(registryID string, registryConfig *RegistryConfig) *RootConfigBuilder {
 	rb.rootConfig.Registries[registryID] = registryConfig
 	return rb
 }
@@ -266,7 +264,7 @@
 	return rb
 }
 
-func (rb *RootConfigBuilder) SetRegistries(registries map[string]*registry.RegistryConfig) *RootConfigBuilder {
+func (rb *RootConfigBuilder) SetRegistries(registries map[string]*RegistryConfig) *RootConfigBuilder {
 	rb.rootConfig.Registries = registries
 	return rb
 }
diff --git a/config/root_config_test.go b/config/root_config_test.go
index 42e27f7..e49e145 100644
--- a/config/root_config_test.go
+++ b/config/root_config_test.go
@@ -30,12 +30,11 @@
 import (
 	"dubbo.apache.org/dubbo-go/v3/common/constant"
 	"dubbo.apache.org/dubbo-go/v3/config_center"
-	"dubbo.apache.org/dubbo-go/v3/registry"
 )
 
 func TestGoConfigProcess(t *testing.T) {
 	rc := &RootConfigBuilder{rootConfig: newEmptyRootConfig()}
-	r := &registry.RegistryConfig{Protocol: "zookeeper", Timeout: "10s", Address: "127.0.0.1:2181"}
+	r := &RegistryConfig{Protocol: "zookeeper", Timeout: "10s", Address: "127.0.0.1:2181"}
 	rc.AddRegistry("demoZK", r)
 
 	// test koan.UnmarshalWithConf error
@@ -65,7 +64,7 @@
 		AddProtocol("dubbo", protocolConfig).
 		AddRegistry("nacos", registryConfig).
 		SetProtocols(map[string]*ProtocolConfig{"dubbo": protocolConfig}).
-		SetRegistries(map[string]*registry.RegistryConfig{"nacos": registryConfig}).
+		SetRegistries(map[string]*RegistryConfig{"nacos": registryConfig}).
 		SetProvider(NewProviderConfigBuilder().Build()).
 		SetConsumer(NewConsumerConfigBuilder().Build()).
 		SetMetric(NewMetricConfigBuilder().Build()).
diff --git a/config/service.go b/config/service.go
index 0621bc2..513048a 100644
--- a/config/service.go
+++ b/config/service.go
@@ -26,19 +26,16 @@
 )
 
 import (
-	"dubbo.apache.org/dubbo-go/v3/client"
 	"dubbo.apache.org/dubbo-go/v3/common"
 )
 
 var (
-	conServicesLock              = sync.Mutex{}                               // used to guard conServices map.
-	conServices                  = map[string]common.RPCService{}             // service name -> service
-	proServicesLock              = sync.Mutex{}                               // used to guard proServices map
-	proServices                  = map[string]common.RPCService{}             // service name -> service
-	interfaceNameConServicesLock = sync.Mutex{}                               // used to guard interfaceNameConServices map
-	interfaceNameConServices     = map[string]common.RPCService{}             // interfaceName -> service
-	clientInfoServicesLock       = sync.Mutex{}                               // used to guard clientInfoServices map
-	clientInfoServices           = map[*client.ClientInfo]common.RPCService{} // ClientInfo -> service
+	conServicesLock              = sync.Mutex{}                   // used to guard conServices map.
+	conServices                  = map[string]common.RPCService{} // service name -> service
+	proServicesLock              = sync.Mutex{}                   // used to guard proServices map
+	proServices                  = map[string]common.RPCService{} // service name -> service
+	interfaceNameConServicesLock = sync.Mutex{}                   // used to guard interfaceNameConServices map
+	interfaceNameConServices     = map[string]common.RPCService{} // interfaceName -> service
 )
 
 // SetConsumerService is called by init() of implement of RPCService
@@ -110,17 +107,9 @@
 	return nil
 }
 
-// SetClientInfoService set new info and service into clientInfosServices if new info and service are not nil
-func SetClientInfoService(info *client.ClientInfo, srv common.RPCService) {
-	if info == nil || info.ClientInjectFunc == nil || srv == nil {
-		return
-	}
-	clientInfoServicesLock.Lock()
-	defer clientInfoServicesLock.Unlock()
-	clientInfoServices[info] = srv
-}
-
-// GetClientInfoServicesMap returns clientInfoServices
-func GetClientInfoServicesMap() map[*client.ClientInfo]common.RPCService {
-	return clientInfoServices
-}
+// SetClientInfoService is used by new Triple generated code
+// use interface{} to represent info because config package can not depend on client package.
+// When refactoring work finished, this info should be with *client.ClientInfo type and this
+// function would be implemented.
+// todo(DMWangnima): refactor and implement this function
+func SetClientInfoService(info interface{}, service common.RPCService) {}
diff --git a/config/service_config.go b/config/service_config.go
index fb97233..6689810 100644
--- a/config/service_config.go
+++ b/config/service_config.go
@@ -209,7 +209,12 @@
 func getRandomPort(protocolConfigs []*ProtocolConfig) *list.List {
 	ports := list.New()
 	for _, proto := range protocolConfigs {
-		if len(proto.Port) > 0 {
+		if port, err := strconv.Atoi(proto.Port); err != nil {
+			logger.Infof(
+				"%s will be assgined to a random port, since the port is an invalid number",
+				proto.Name,
+			)
+		} else if port > 0 {
 			continue
 		}
 
@@ -238,7 +243,7 @@
 
 	regUrls := make([]*common.URL, 0)
 	if !s.NotRegister {
-		regUrls = loadRegistries(s.RegistryIDs, s.RCRegistriesMap, common.PROVIDER)
+		regUrls = LoadRegistries(s.RegistryIDs, s.RCRegistriesMap, common.PROVIDER)
 	}
 
 	urlMap := s.getUrlMap()
diff --git a/config/service_config_test.go b/config/service_config_test.go
index da6b5af..3d6494d 100644
--- a/config/service_config_test.go
+++ b/config/service_config_test.go
@@ -93,8 +93,8 @@
 		assert.Equal(t, serviceConfig.IsExport(), false)
 	})
 
-	t.Run("loadRegistries&loadProtocol&getRandomPort", func(t *testing.T) {
-		registries := loadRegistries(serviceConfig.RegistryIDs, serviceConfig.RCRegistriesMap, common.PROVIDER)
+	t.Run("LoadRegistries&loadProtocol&getRandomPort", func(t *testing.T) {
+		registries := LoadRegistries(serviceConfig.RegistryIDs, serviceConfig.RCRegistriesMap, common.PROVIDER)
 		assert.Equal(t, len(registries), 1)
 		assert.Equal(t, "service-discovery-registry", registries[0].Protocol)
 		assert.Equal(t, registries[0].Port, "8848")
diff --git a/protocol/triple/triple-tool/protoc-gen-triple/main.go b/protocol/triple/triple-tool/protoc-gen-triple/main.go
index 7f7ea59..4a60279 100644
--- a/protocol/triple/triple-tool/protoc-gen-triple/main.go
+++ b/protocol/triple/triple-tool/protoc-gen-triple/main.go
@@ -18,15 +18,22 @@
 package main
 
 import (
-	"dubbo.apache.org/dubbo-go/v3/triple-tool/gen/generator"
-	"dubbo.apache.org/dubbo-go/v3/triple-tool/internal/version"
 	"fmt"
-	"google.golang.org/protobuf/compiler/protogen"
-	"google.golang.org/protobuf/types/pluginpb"
 	"os"
 	"path/filepath"
 )
 
+import (
+	"google.golang.org/protobuf/compiler/protogen"
+
+	"google.golang.org/protobuf/types/pluginpb"
+)
+
+import (
+	"dubbo.apache.org/dubbo-go/v3/triple-tool/gen/generator"
+	"dubbo.apache.org/dubbo-go/v3/triple-tool/internal/version"
+)
+
 const (
 	usage = "See https://connect.build/docs/go/getting-started to learn how to use this plugin.\n\nFlags:\n  -h, --help\tPrint this help and exit.\n      --version\tPrint the version and exit."
 )
diff --git a/protocol/triple/triple-tool/util/module.go b/protocol/triple/triple-tool/util/module.go
index d871c9a..1157598 100644
--- a/protocol/triple/triple-tool/util/module.go
+++ b/protocol/triple/triple-tool/util/module.go
@@ -17,7 +17,9 @@
 
 package util
 
-import "strings"
+import (
+	"strings"
+)
 
 func GetModuleName() (string, error) {
 	output, err := Exec("go list -m", "./")
diff --git a/registry/registry_config.go b/registry/registry_config.go
index 7ecac63..ae1ac66 100644
--- a/registry/registry_config.go
+++ b/registry/registry_config.go
@@ -17,27 +17,9 @@
 
 package registry
 
-import (
-	"net/url"
-	"strconv"
-	"strings"
-)
-
-import (
-	"github.com/creasty/defaults"
-
-	"github.com/dubbogo/gost/log/logger"
-
-	perrors "github.com/pkg/errors"
-)
-
-import (
-	"dubbo.apache.org/dubbo-go/v3/common"
-	commonCfg "dubbo.apache.org/dubbo-go/v3/common/config"
-	"dubbo.apache.org/dubbo-go/v3/common/constant"
-	"dubbo.apache.org/dubbo-go/v3/common/extension"
-	"dubbo.apache.org/dubbo-go/v3/config/instance"
-)
+// todo(DMwangnima): finish refactoring and move related logic from config package to this file.
+// This RegistryConfig is a copy of /config/RegistryConfig right now.
+// Please refer to issue(https://github.com/apache/dubbo-go/issues/2377).
 
 // RegistryConfig is the configuration of the registry center
 type RegistryConfig struct {
@@ -58,216 +40,3 @@
 	UseAsMetaReport   bool              `default:"true" yaml:"use-as-meta-report" json:"use-as-meta-report,omitempty" property:"use-as-meta-report"`
 	UseAsConfigCenter bool              `default:"true" yaml:"use-as-config-center" json:"use-as-config-center,omitempty" property:"use-as-config-center"`
 }
-
-// Prefix dubbo.registries
-func (RegistryConfig) Prefix() string {
-	return constant.RegistryConfigPrefix
-}
-
-func (c *RegistryConfig) Init() error {
-	if err := defaults.Set(c); err != nil {
-		return err
-	}
-	return c.startRegistryConfig()
-}
-
-func (c *RegistryConfig) getUrlMap(roleType common.RoleType) url.Values {
-	urlMap := url.Values{}
-	urlMap.Set(constant.RegistryGroupKey, c.Group)
-	urlMap.Set(constant.RegistryRoleKey, strconv.Itoa(int(roleType)))
-	urlMap.Set(constant.RegistryKey, c.Protocol)
-	urlMap.Set(constant.RegistryTimeoutKey, c.Timeout)
-	// multi registry invoker weight label for load balance
-	urlMap.Set(constant.RegistryKey+"."+constant.RegistryLabelKey, strconv.FormatBool(true))
-	urlMap.Set(constant.RegistryKey+"."+constant.PreferredKey, strconv.FormatBool(c.Preferred))
-	urlMap.Set(constant.RegistryKey+"."+constant.RegistryZoneKey, c.Zone)
-	urlMap.Set(constant.RegistryKey+"."+constant.WeightKey, strconv.FormatInt(c.Weight, 10))
-	urlMap.Set(constant.RegistryTTLKey, c.TTL)
-	urlMap.Set(constant.ClientNameKey, ClientNameID(c, c.Protocol, c.Address))
-
-	for k, v := range c.Params {
-		urlMap.Set(k, v)
-	}
-	return urlMap
-}
-
-func (c *RegistryConfig) startRegistryConfig() error {
-	c.translateRegistryAddress()
-	if c.UseAsMetaReport && commonCfg.IsValid(c.Address) {
-		if tmpUrl, err := c.toMetadataReportUrl(); err == nil {
-			instance.SetMetadataReportInstanceByReg(tmpUrl)
-		} else {
-			return perrors.Wrap(err, "Start RegistryConfig failed.")
-		}
-	}
-	return commonCfg.Verify(c)
-}
-
-// toMetadataReportUrl translate the registry configuration to the metadata reporting url
-func (c *RegistryConfig) toMetadataReportUrl() (*common.URL, error) {
-	res, err := common.NewURL(c.Address,
-		common.WithLocation(c.Address),
-		common.WithProtocol(c.Protocol),
-		common.WithUsername(c.Username),
-		common.WithPassword(c.Password),
-		common.WithParamsValue(constant.TimeoutKey, c.Timeout),
-		common.WithParamsValue(constant.ClientNameKey, ClientNameID(c, c.Protocol, c.Address)),
-		common.WithParamsValue(constant.MetadataReportGroupKey, c.Group),
-		common.WithParamsValue(constant.MetadataReportNamespaceKey, c.Namespace),
-	)
-	if err != nil || len(res.Protocol) == 0 {
-		return nil, perrors.New("Invalid Registry Config.")
-	}
-	return res, nil
-}
-
-// translateRegistryAddress translate registry address
-//
-//	eg:address=nacos://127.0.0.1:8848 will return 127.0.0.1:8848 and protocol will set nacos
-func (c *RegistryConfig) translateRegistryAddress() string {
-	if strings.Contains(c.Address, "://") {
-		u, err := url.Parse(c.Address)
-		if err != nil {
-			logger.Errorf("The registry url is invalid, error: %#v", err)
-			panic(err)
-		}
-		c.Protocol = u.Scheme
-		c.Address = strings.Join([]string{u.Host, u.Path}, "")
-	}
-	return c.Address
-}
-
-func (c *RegistryConfig) GetInstance(roleType common.RoleType) (Registry, error) {
-	u, err := c.toURL(roleType)
-	if err != nil {
-		return nil, err
-	}
-	// if the protocol == registry, set protocol the registry value in url.params
-	if u.Protocol == constant.RegistryProtocol {
-		u.Protocol = u.GetParam(constant.RegistryKey, "")
-	}
-	return extension.GetRegistry(u.Protocol, u)
-}
-
-func (c *RegistryConfig) toURL(roleType common.RoleType) (*common.URL, error) {
-	address := c.translateRegistryAddress()
-	var registryURLProtocol string
-	if c.RegistryType == constant.RegistryTypeService {
-		// service discovery protocol
-		registryURLProtocol = constant.ServiceRegistryProtocol
-	} else if c.RegistryType == constant.RegistryTypeInterface {
-		registryURLProtocol = constant.RegistryProtocol
-	} else {
-		registryURLProtocol = constant.ServiceRegistryProtocol
-	}
-	return common.NewURL(registryURLProtocol+"://"+address,
-		common.WithParams(c.getUrlMap(roleType)),
-		common.WithParamsValue(constant.RegistrySimplifiedKey, strconv.FormatBool(c.Simplified)),
-		common.WithParamsValue(constant.RegistryKey, c.Protocol),
-		common.WithParamsValue(constant.RegistryNamespaceKey, c.Namespace),
-		common.WithParamsValue(constant.RegistryTimeoutKey, c.Timeout),
-		common.WithUsername(c.Username),
-		common.WithPassword(c.Password),
-		common.WithLocation(c.Address),
-	)
-}
-
-func (c *RegistryConfig) ToURLs(roleType common.RoleType) ([]*common.URL, error) {
-	address := c.translateRegistryAddress()
-	var urls []*common.URL
-	var err error
-	var registryURL *common.URL
-
-	if !commonCfg.IsValid(c.Address) {
-		logger.Infof("Empty or N/A registry address found, the process will work with no registry enabled " +
-			"which means that the address of this instance will not be registered and not able to be found by other consumer instances.")
-		return urls, nil
-	}
-
-	if c.RegistryType == constant.RegistryTypeService {
-		// service discovery protocol
-		if registryURL, err = c.createNewURL(constant.ServiceRegistryProtocol, address, roleType); err == nil {
-			urls = append(urls, registryURL)
-		}
-	} else if c.RegistryType == constant.RegistryTypeInterface {
-		if registryURL, err = c.createNewURL(constant.RegistryProtocol, address, roleType); err == nil {
-			urls = append(urls, registryURL)
-		}
-	} else if c.RegistryType == constant.RegistryTypeAll {
-		if registryURL, err = c.createNewURL(constant.ServiceRegistryProtocol, address, roleType); err == nil {
-			urls = append(urls, registryURL)
-		}
-		if registryURL, err = c.createNewURL(constant.RegistryProtocol, address, roleType); err == nil {
-			urls = append(urls, registryURL)
-		}
-	} else {
-		if registryURL, err = c.createNewURL(constant.ServiceRegistryProtocol, address, roleType); err == nil {
-			urls = append(urls, registryURL)
-		}
-	}
-	return urls, err
-}
-
-func LoadRegistries(registryIds []string, registries map[string]*RegistryConfig, roleType common.RoleType) []*common.URL {
-	var registryURLs []*common.URL
-	//trSlice := strings.Split(targetRegistries, ",")
-
-	for k, registryConf := range registries {
-		target := false
-
-		// if user not config targetRegistries, default load all
-		// Notice: in func "func Split(s, sep string) []string" comment:
-		// if s does not contain sep and sep is not empty, SplitAfter returns
-		// a slice of length 1 whose only element is s. So we have to add the
-		// condition when targetRegistries string is not set (it will be "" when not set)
-		if len(registryIds) == 0 || (len(registryIds) == 1 && registryIds[0] == "") {
-			target = true
-		} else {
-			// else if user config targetRegistries
-			for _, tr := range registryIds {
-				if tr == k {
-					target = true
-					break
-				}
-			}
-		}
-
-		if target {
-			if urls, err := registryConf.ToURLs(roleType); err != nil {
-				logger.Errorf("The registry id: %s url is invalid, error: %#v", k, err)
-				panic(err)
-			} else {
-				registryURLs = append(registryURLs, urls...)
-			}
-		}
-	}
-
-	return registryURLs
-}
-
-// ClientNameID unique identifier id for client
-func ClientNameID(config *RegistryConfig, protocol, address string) string {
-	return strings.Join([]string{config.Prefix(), protocol, address}, "-")
-}
-
-func (c *RegistryConfig) createNewURL(protocol string, address string, roleType common.RoleType) (*common.URL, error) {
-	return common.NewURL(protocol+"://"+address,
-		common.WithParams(c.getUrlMap(roleType)),
-		common.WithParamsValue(constant.RegistrySimplifiedKey, strconv.FormatBool(c.Simplified)),
-		common.WithParamsValue(constant.RegistryKey, c.Protocol),
-		common.WithParamsValue(constant.RegistryNamespaceKey, c.Namespace),
-		common.WithParamsValue(constant.RegistryTimeoutKey, c.Timeout),
-		common.WithUsername(c.Username),
-		common.WithPassword(c.Password),
-		common.WithLocation(c.Address),
-	)
-}
-
-// DynamicUpdateProperties update registry
-func (c *RegistryConfig) DynamicUpdateProperties(updateRegistryConfig *RegistryConfig) {
-	// if nacos's registry timeout not equal local root config's registry timeout , update.
-	if updateRegistryConfig != nil && updateRegistryConfig.Timeout != c.Timeout {
-		c.Timeout = updateRegistryConfig.Timeout
-		logger.Infof("RegistryConfigs Timeout was dynamically updated, new value:%v", c.Timeout)
-	}
-}
diff --git a/registry/registry_config_test.go b/registry/registry_config_test.go
deleted file mode 100644
index ab9a874..0000000
--- a/registry/registry_config_test.go
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package registry
-
-import (
-	"testing"
-)
-
-import (
-	"github.com/stretchr/testify/assert"
-)
-
-import (
-	"dubbo.apache.org/dubbo-go/v3/common"
-	"dubbo.apache.org/dubbo-go/v3/common/constant"
-)
-
-func TestLoadRegistries(t *testing.T) {
-	target := []string{"shanghai1"}
-	regs := map[string]*RegistryConfig{
-
-		"shanghai1": {
-			Protocol: "mock",
-			Timeout:  "2s",
-			Group:    "shanghai_idc",
-			Address:  "127.0.0.2:2181,128.0.0.1:2181",
-			Username: "user1",
-			Password: "pwd1",
-		},
-	}
-	urls := LoadRegistries(target, regs, common.CONSUMER)
-	t.Logf("loadRegistries() = urls:%v", urls)
-	assert.Equal(t, "127.0.0.2:2181,128.0.0.1:2181", urls[0].Location)
-}
-
-func TestLoadRegistries1(t *testing.T) {
-	target := []string{"shanghai1"}
-	regs := map[string]*RegistryConfig{
-
-		"shanghai1": {
-			Protocol: "mock",
-			Timeout:  "2s",
-			Group:    "shanghai_idc",
-			Address:  "127.0.0.2:2181",
-			Username: "user1",
-			Password: "pwd1",
-		},
-	}
-	urls := LoadRegistries(target, regs, common.CONSUMER)
-	t.Logf("loadRegistries() = urls:%v", urls)
-	assert.Equal(t, "127.0.0.2:2181", urls[0].Location)
-}
-
-func TestRegistryTypeAll(t *testing.T) {
-	target := []string{"test"}
-	regs := map[string]*RegistryConfig{
-		"test": {
-			Protocol:     "mock",
-			Address:      "127.0.0.2:2181",
-			RegistryType: constant.RegistryTypeAll,
-		},
-	}
-	urls := LoadRegistries(target, regs, common.PROVIDER)
-	assert.Equal(t, 2, len(urls))
-}
-
-func TestTranslateRegistryAddress(t *testing.T) {
-	reg := new(RegistryConfig)
-	reg.Address = "nacos://127.0.0.1:8848"
-
-	reg.translateRegistryAddress()
-
-	assert.Equal(t, "nacos", reg.Protocol)
-	assert.Equal(t, "127.0.0.1:8848", reg.Address)
-}