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

xuetaoli pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/dubbo-go.git


The following commit(s) were added to refs/heads/develop by this push:
     new 0026310a4 chore: update tag and polaris from config to global (#3029)
0026310a4 is described below

commit 0026310a4a9e208c45a4f7d53889e3393c947bbc
Author: Zerui Yang <[email protected]>
AuthorDate: Sun Nov 16 20:09:14 2025 +0800

    chore: update tag and polaris from config to global (#3029)
    
    * fix(router): enhance router configuration with global
---
 client/action.go                  |   1 +
 client/client.go                  |   1 +
 client/options.go                 |  52 ++++++++++++---
 cluster/router/affinity/router.go |  14 ++--
 cluster/router/config.go          |  32 ---------
 cluster/router/polaris/factory.go |   4 +-
 cluster/router/polaris/router.go  |  60 ++++++++++++-----
 cluster/router/tag/match.go       |   8 +--
 cluster/router/tag/router.go      |   8 +--
 cluster/router/tag/router_test.go |  32 ++++-----
 common/constant/key.go            |   5 +-
 global/registry_config.go         |  17 +++++
 global/router_config.go           | 134 ++++++++++++++++++++++++++++++++++++++
 options.go                        |   2 +-
 registry/directory/directory.go   |  40 ++++++++++++
 15 files changed, 315 insertions(+), 95 deletions(-)

diff --git a/client/action.go b/client/action.go
index f66547f15..1c85908cf 100644
--- a/client/action.go
+++ b/client/action.go
@@ -149,6 +149,7 @@ func (refOpts *ReferenceOptions) refer(srv 
common.RPCService, info *ClientInfo)
                // TODO: remove ISIDL after old triple removed
                common.WithParamsValue(constant.IDLMode, ref.IDLMode),
                common.WithAttribute(constant.ConsumerConfigKey, 
refOpts.Consumer),
+               common.WithAttribute(constant.RegistriesConfigKey, 
refOpts.Registries),
        )
 
        // for new triple IDL mode
diff --git a/client/client.go b/client/client.go
index 1fddf423e..6fb0c7104 100644
--- a/client/client.go
+++ b/client/client.go
@@ -165,6 +165,7 @@ func (cli *Client) dial(interfaceName string, info 
*ClientInfo, srv any, opts ..
                setReference(cli.cliOpts.overallReference),
                setApplicationCompat(cli.cliOpts.applicationCompat),
                setRegistriesCompat(cli.cliOpts.registriesCompat),
+               setRegistries(cli.cliOpts.Registries),
                setConsumer(cli.cliOpts.Consumer),
                setMetrics(cli.cliOpts.Metrics),
                setOtel(cli.cliOpts.Otel),
diff --git a/client/options.go b/client/options.go
index bcefc3c2d..b6dd1f7ae 100644
--- a/client/options.go
+++ b/client/options.go
@@ -41,11 +41,12 @@ import (
 )
 
 type ReferenceOptions struct {
-       Reference *global.ReferenceConfig
-       Consumer  *global.ConsumerConfig
-       Metrics   *global.MetricsConfig
-       Otel      *global.OtelConfig
-       TLS       *global.TLSConfig
+       Reference  *global.ReferenceConfig
+       Consumer   *global.ConsumerConfig
+       Metrics    *global.MetricsConfig
+       Otel       *global.OtelConfig
+       TLS        *global.TLSConfig
+       Registries map[string]*global.RegistryConfig
 
        pxy          *proxy.Proxy
        id           string
@@ -61,10 +62,11 @@ type ReferenceOptions struct {
 
 func defaultReferenceOptions() *ReferenceOptions {
        return &ReferenceOptions{
-               Reference: global.DefaultReferenceConfig(),
-               Metrics:   global.DefaultMetricsConfig(),
-               Otel:      global.DefaultOtelConfig(),
-               TLS:       global.DefaultTLSConfig(),
+               Reference:  global.DefaultReferenceConfig(),
+               Metrics:    global.DefaultMetricsConfig(),
+               Otel:       global.DefaultOtelConfig(),
+               TLS:        global.DefaultTLSConfig(),
+               Registries: global.DefaultRegistriesConfig(),
        }
 }
 
@@ -107,6 +109,19 @@ func (refOpts *ReferenceOptions) init(opts 
...ReferenceOption) error {
        }
 
        // init registries
+       // convert Registries to registriesCompat
+       if len(refOpts.Registries) > 0 {
+               if refOpts.registriesCompat == nil {
+                       refOpts.registriesCompat = 
make(map[string]*config.RegistryConfig)
+               }
+               for id, reg := range refOpts.Registries {
+                       refOpts.registriesCompat[id] = compatRegistryConfig(reg)
+                       if err := refOpts.registriesCompat[id].Init(); err != 
nil {
+                               return err
+                       }
+               }
+       }
+
        if len(refOpts.registriesCompat) > 0 {
                regs := refOpts.registriesCompat
                if len(refConf.RegistryIDs) <= 0 {
@@ -193,6 +208,17 @@ func WithRegistryIDs(registryIDs ...string) 
ReferenceOption {
        }
 }
 
+func WithRegistry(opts ...registry.Option) ReferenceOption {
+       regOpts := registry.NewOptions(opts...)
+
+       return func(refOpts *ReferenceOptions) {
+               if refOpts.Registries == nil {
+                       refOpts.Registries = 
make(map[string]*global.RegistryConfig)
+               }
+               refOpts.Registries[regOpts.ID] = regOpts.Registry
+       }
+}
+
 // ========== Cluster Strategy ==========
 
 func WithClusterAvailable() ReferenceOption {
@@ -478,6 +504,12 @@ func setTLS(tls *global.TLSConfig) ReferenceOption {
        }
 }
 
+func setRegistries(regs map[string]*global.RegistryConfig) ReferenceOption {
+       return func(opts *ReferenceOptions) {
+               opts.Registries = regs
+       }
+}
+
 type ClientOptions struct {
        Consumer    *global.ConsumerConfig
        Application *global.ApplicationConfig
@@ -495,7 +527,7 @@ type ClientOptions struct {
 func defaultClientOptions() *ClientOptions {
        return &ClientOptions{
                Consumer:         global.DefaultConsumerConfig(),
-               Registries:       make(map[string]*global.RegistryConfig),
+               Registries:       global.DefaultRegistriesConfig(),
                Application:      global.DefaultApplicationConfig(),
                Shutdown:         global.DefaultShutdownConfig(),
                Metrics:          global.DefaultMetricsConfig(),
diff --git a/cluster/router/affinity/router.go 
b/cluster/router/affinity/router.go
index 0b69bfe50..d6687902f 100644
--- a/cluster/router/affinity/router.go
+++ b/cluster/router/affinity/router.go
@@ -30,7 +30,6 @@ import (
 )
 
 import (
-       "dubbo.apache.org/dubbo-go/v3/cluster/router"
        "dubbo.apache.org/dubbo-go/v3/cluster/router/condition"
        "dubbo.apache.org/dubbo-go/v3/common"
        conf "dubbo.apache.org/dubbo-go/v3/common/config"
@@ -85,14 +84,13 @@ type ApplicationAffinityRoute struct {
 
 func newApplicationAffinityRouter(url *common.URL) *ApplicationAffinityRoute {
 
-       application, ok := url.GetAttribute(constant.ApplicationKey)
-       if !ok {
-               logger.Warnf("ApplicationAffinityRoute url does not have 
application attribute, url=%s", url)
+       applicationName := url.GetParam(constant.ApplicationKey, "")
+
+       if applicationName == "" {
+               logger.Errorf("Application affinity router must set application 
name")
                return nil
        }
 
-       applicationName := application.(global.ApplicationConfig).Name
-
        a := &ApplicationAffinityRoute{
                currentApplication: applicationName,
        }
@@ -225,8 +223,8 @@ func (a *affinityRoute) Notify(_ []base.Invoker) {
        panic("this function should not be called")
 }
 
-func parseConfig(c string) (router.AffinityRouter, error) {
-       res := router.AffinityRouter{}
+func parseConfig(c string) (global.AffinityRouter, error) {
+       res := global.AffinityRouter{}
        err := yaml.Unmarshal([]byte(c), &res)
        return res, err
 }
diff --git a/cluster/router/config.go b/cluster/router/config.go
deleted file mode 100644
index 2231898c2..000000000
--- a/cluster/router/config.go
+++ /dev/null
@@ -1,32 +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 router
-
-type AffinityAware struct {
-       Key   string `default:"" yaml:"key" json:"key,omitempty" property:"key"`
-       Ratio int32  `default:"0" yaml:"ratio" json:"ratio,omitempty" 
property:"ratio"`
-}
-
-// AffinityRouter -- RouteConfigVersion == v3.1
-type AffinityRouter struct {
-       Scope         string        `validate:"required" yaml:"scope" 
json:"scope,omitempty" property:"scope"` // must be chosen from `service` and 
`application`.
-       Key           string        `validate:"required" yaml:"key" 
json:"key,omitempty" property:"key"`       // specifies which service or 
application the rule body acts on.
-       Runtime       bool          `default:"false" yaml:"runtime" 
json:"runtime,omitempty" property:"runtime"`
-       Enabled       bool          `default:"true" yaml:"enabled" 
json:"enabled,omitempty" property:"enabled"`
-       AffinityAware AffinityAware `yaml:"affinityAware" 
json:"affinityAware,omitempty" property:"affinityAware"`
-}
diff --git a/cluster/router/polaris/factory.go 
b/cluster/router/polaris/factory.go
index 0eeb6fdcb..3f6fc9c2a 100644
--- a/cluster/router/polaris/factory.go
+++ b/cluster/router/polaris/factory.go
@@ -31,6 +31,6 @@ func NewPolarisRouterFactory() router.PriorityRouterFactory {
 }
 
 // NewPriorityRouter construct a new PriorityRouter
-func (f *RouteFactory) NewPriorityRouter(_ *common.URL) 
(router.PriorityRouter, error) {
-       return newPolarisRouter()
+func (f *RouteFactory) NewPriorityRouter(url *common.URL) 
(router.PriorityRouter, error) {
+       return newPolarisRouter(url)
 }
diff --git a/cluster/router/polaris/router.go b/cluster/router/polaris/router.go
index 317ea16dd..98f41966e 100644
--- a/cluster/router/polaris/router.go
+++ b/cluster/router/polaris/router.go
@@ -21,6 +21,7 @@ import (
        "errors"
        "fmt"
        "strings"
+       "sync"
        "time"
 )
 
@@ -36,7 +37,7 @@ import (
        "dubbo.apache.org/dubbo-go/v3/cluster/router"
        "dubbo.apache.org/dubbo-go/v3/common"
        "dubbo.apache.org/dubbo-go/v3/common/constant"
-       "dubbo.apache.org/dubbo-go/v3/config"
+       "dubbo.apache.org/dubbo-go/v3/global"
        "dubbo.apache.org/dubbo-go/v3/protocol/base"
        remotingpolaris "dubbo.apache.org/dubbo-go/v3/remoting/polaris"
        "dubbo.apache.org/dubbo-go/v3/remoting/polaris/parser"
@@ -50,7 +51,21 @@ var (
        ErrorPolarisServiceRouteRuleEmpty = errors.New("service route rule is 
empty")
 )
 
-func newPolarisRouter() (*polarisRouter, error) {
+func newPolarisRouter(url *common.URL) (*polarisRouter, error) {
+
+       // get from url param
+       applicationName := url.GetParam(constant.ApplicationKey, "")
+
+       if applicationName == "" {
+               return nil, fmt.Errorf("polaris router must set application 
name")
+       }
+
+       // get from url attr
+       registries, ok := url.GetAttribute(constant.RegistriesConfigKey)
+       if !ok {
+               registries = make(map[string]*global.RegistryConfig)
+       }
+
        if err := remotingpolaris.Check(); errors.Is(err, 
remotingpolaris.ErrorNoOpenPolarisAbility) {
                return &polarisRouter{
                        openRoute: false,
@@ -67,9 +82,11 @@ func newPolarisRouter() (*polarisRouter, error) {
        }
 
        return &polarisRouter{
-               openRoute:   true,
-               routerAPI:   routerAPI,
-               consumerAPI: consumerAPI,
+               openRoute:          true,
+               routerAPI:          routerAPI,
+               consumerAPI:        consumerAPI,
+               currentApplication: applicationName,
+               Registries:         
registries.(map[string]*global.RegistryConfig),
        }, nil
 }
 
@@ -78,6 +95,11 @@ type polarisRouter struct {
 
        routerAPI   polaris.RouterAPI
        consumerAPI polaris.ConsumerAPI
+
+       // config change: config to global
+       mu                 sync.RWMutex
+       currentApplication string
+       Registries         map[string]*global.RegistryConfig
 }
 
 // Route Determine the target invokers list.
@@ -94,7 +116,7 @@ func (p *polarisRouter) Route(invokers []base.Invoker, url 
*common.URL,
                return invokers
        }
 
-       service := getService(url)
+       service := p.getService(url)
        instanceMap := p.buildInstanceMap(service)
        if len(instanceMap) == 0 {
                return invokers
@@ -138,17 +160,20 @@ func (p *polarisRouter) Route(invokers []base.Invoker, 
url *common.URL,
        return ret
 }
 
-func getService(url *common.URL) string {
+func (p *polarisRouter) getService(url *common.URL) string {
+       p.mu.RLock()
+       defer p.mu.RUnlock()
+
        applicationMode := false
-       for _, item := range config.GetRootConfig().Registries {
-               if item.Protocol == constant.PolarisKey {
+       for _, item := range p.Registries {
+               if item != nil && item.Protocol == constant.PolarisKey {
                        applicationMode = item.RegistryType == 
constant.ServiceKey
                }
        }
 
        service := url.Interface()
        if applicationMode {
-               service = config.GetApplicationConfig().Name
+               service = p.currentApplication
        }
 
        return service
@@ -176,7 +201,7 @@ func (p *polarisRouter) buildRouteRequest(svc string, url 
*common.URL,
        for i := range labels {
                label := labels[i]
                if strings.Compare(label, model.LabelKeyPath) == 0 {
-                       
routeReq.AddArguments(model.BuildPathArgument(getInvokeMethod(url, invocation)))
+                       
routeReq.AddArguments(model.BuildPathArgument(p.getInvokeMethod(url, 
invocation)))
                        continue
                }
                if strings.HasPrefix(label, model.LabelKeyHeader) {
@@ -215,15 +240,18 @@ func (p *polarisRouter) buildTrafficLabels(svc string) 
([]string, error) {
        routeRule := resp.GetValue().(*v1.Routing)
        labels := make([]string, 0, 4)
        labels = append(labels, collectRouteLabels(routeRule.GetInbounds())...)
-       labels = append(labels, collectRouteLabels(routeRule.GetInbounds())...)
+       labels = append(labels, collectRouteLabels(routeRule.GetOutbounds())...)
 
        return labels, nil
 }
 
-func getInvokeMethod(url *common.URL, invoaction base.Invocation) string {
+func (p *polarisRouter) getInvokeMethod(url *common.URL, invoaction 
base.Invocation) string {
+       p.mu.RLock()
+       defer p.mu.RUnlock()
+
        applicationMode := false
-       for _, item := range config.GetRootConfig().Registries {
-               if item.Protocol == constant.PolarisKey {
+       for _, item := range p.Registries {
+               if item != nil && item.Protocol == constant.PolarisKey {
                        applicationMode = item.RegistryType == 
constant.ServiceKey
                }
        }
@@ -293,7 +321,7 @@ func (p *polarisRouter) Notify(invokers []base.Invoker) {
        if len(invokers) == 0 {
                return
        }
-       service := getService(invokers[0].GetURL())
+       service := p.getService(invokers[0].GetURL())
        if service == "" {
                logger.Error("url service is empty")
                return
diff --git a/cluster/router/tag/match.go b/cluster/router/tag/match.go
index 60739ef2d..e8208848c 100644
--- a/cluster/router/tag/match.go
+++ b/cluster/router/tag/match.go
@@ -28,7 +28,7 @@ import (
 import (
        "dubbo.apache.org/dubbo-go/v3/common"
        "dubbo.apache.org/dubbo-go/v3/common/constant"
-       "dubbo.apache.org/dubbo-go/v3/config"
+       "dubbo.apache.org/dubbo-go/v3/global"
        "dubbo.apache.org/dubbo-go/v3/protocol/base"
 )
 
@@ -62,7 +62,7 @@ func staticTag(invokers []base.Invoker, url *common.URL, 
invocation base.Invocat
 }
 
 // dynamic tag matching. used configuration center to create tag router 
configuration
-func dynamicTag(invokers []base.Invoker, url *common.URL, invocation 
base.Invocation, cfg config.RouterConfig) []base.Invoker {
+func dynamicTag(invokers []base.Invoker, url *common.URL, invocation 
base.Invocation, cfg global.RouterConfig) []base.Invoker {
        tag := invocation.GetAttachmentWithDefaultValue(constant.Tagkey, 
url.GetParam(constant.Tagkey, ""))
        if tag == "" {
                return requestEmptyTag(invokers, cfg)
@@ -73,7 +73,7 @@ func dynamicTag(invokers []base.Invoker, url *common.URL, 
invocation base.Invoca
 // if request.tag is not set, only providers with empty tags will be matched.
 // even if a service is available in the cluster, it cannot be invoked if the 
tag does not match,
 // and requests without tags or other tags will never be able to access 
services with other tags.
-func requestEmptyTag(invokers []base.Invoker, cfg config.RouterConfig) 
[]base.Invoker {
+func requestEmptyTag(invokers []base.Invoker, cfg global.RouterConfig) 
[]base.Invoker {
        result := filterInvokers(invokers, "", func(invoker base.Invoker, tag 
any) bool {
                return invoker.GetURL().GetParam(constant.Tagkey, "") != ""
        })
@@ -95,7 +95,7 @@ func requestEmptyTag(invokers []base.Invoker, cfg 
config.RouterConfig) []base.In
 // if no service corresponding to the request tag exists in the cluster,
 // the provider with the empty request tag is degraded by default.
 // to change the default behavior that no provider matching TAG1 returns an 
exception, set request.tag.force=true.
-func requestTag(invokers []base.Invoker, url *common.URL, invocation 
base.Invocation, cfg config.RouterConfig, tag string) []base.Invoker {
+func requestTag(invokers []base.Invoker, url *common.URL, invocation 
base.Invocation, cfg global.RouterConfig, tag string) []base.Invoker {
        var (
                addresses []string
                result    []base.Invoker
diff --git a/cluster/router/tag/router.go b/cluster/router/tag/router.go
index 825dc080e..8e4fafd26 100644
--- a/cluster/router/tag/router.go
+++ b/cluster/router/tag/router.go
@@ -32,8 +32,8 @@ import (
        "dubbo.apache.org/dubbo-go/v3/common"
        conf "dubbo.apache.org/dubbo-go/v3/common/config"
        "dubbo.apache.org/dubbo-go/v3/common/constant"
-       "dubbo.apache.org/dubbo-go/v3/config"
        "dubbo.apache.org/dubbo-go/v3/config_center"
+       "dubbo.apache.org/dubbo-go/v3/global"
        "dubbo.apache.org/dubbo-go/v3/protocol/base"
        "dubbo.apache.org/dubbo-go/v3/remoting"
 )
@@ -58,7 +58,7 @@ func (p *PriorityRouter) Route(invokers []base.Invoker, url 
*common.URL, invocat
        if !ok {
                return staticTag(invokers, url, invocation)
        }
-       routerCfg := value.(config.RouterConfig)
+       routerCfg := value.(global.RouterConfig)
        if !*routerCfg.Enabled || !*routerCfg.Valid {
                return staticTag(invokers, url, invocation)
        }
@@ -116,9 +116,9 @@ func (p *PriorityRouter) Process(event 
*config_center.ConfigChangeEvent) {
        logger.Infof("[tag router]Parse tag router config 
success,routerConfig=%+v", routerConfig)
 }
 
-func parseRoute(routeContent string) (*config.RouterConfig, error) {
+func parseRoute(routeContent string) (*global.RouterConfig, error) {
        routeDecoder := yaml.NewDecoder(strings.NewReader(routeContent))
-       routerConfig := &config.RouterConfig{}
+       routerConfig := &global.RouterConfig{}
        err := routeDecoder.Decode(routerConfig)
        if err != nil {
                return nil, err
diff --git a/cluster/router/tag/router_test.go 
b/cluster/router/tag/router_test.go
index b30f62c6c..71316f45f 100644
--- a/cluster/router/tag/router_test.go
+++ b/cluster/router/tag/router_test.go
@@ -31,9 +31,9 @@ import (
        common_cfg "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/config_center"
        "dubbo.apache.org/dubbo-go/v3/config_center/configurator"
+       "dubbo.apache.org/dubbo-go/v3/global"
        "dubbo.apache.org/dubbo-go/v3/protocol/base"
        "dubbo.apache.org/dubbo-go/v3/protocol/invocation"
 )
@@ -134,7 +134,7 @@ func TestRouter(t *testing.T) {
        t.Run("dynamicEmptyTag_requestEmptyTag", func(t *testing.T) {
                p, err := NewTagPriorityRouter()
                assert.Nil(t, err)
-               
p.routerConfigs.Store(consumerUrl.Service()+constant.TagRouterRuleSuffix, 
config.RouterConfig{
+               
p.routerConfigs.Store(consumerUrl.Service()+constant.TagRouterRuleSuffix, 
global.RouterConfig{
                        Key:     consumerUrl.Service() + 
constant.TagRouterRuleSuffix,
                        Force:   falsePointer,
                        Enabled: truePointer,
@@ -154,7 +154,7 @@ func TestRouter(t *testing.T) {
        t.Run("dynamicEmptyTag_requestHasTag", func(t *testing.T) {
                p, err := NewTagPriorityRouter()
                assert.Nil(t, err)
-               
p.routerConfigs.Store(consumerUrl.Service()+constant.TagRouterRuleSuffix, 
config.RouterConfig{
+               
p.routerConfigs.Store(consumerUrl.Service()+constant.TagRouterRuleSuffix, 
global.RouterConfig{
                        Key:     consumerUrl.Service() + 
constant.TagRouterRuleSuffix,
                        Force:   falsePointer,
                        Enabled: truePointer,
@@ -175,12 +175,12 @@ func TestRouter(t *testing.T) {
        t.Run("dynamicTag_requestEmptyTag", func(t *testing.T) {
                p, err := NewTagPriorityRouter()
                assert.Nil(t, err)
-               
p.routerConfigs.Store(strings.Join([]string{consumerUrl.GetParam(constant.ApplicationKey,
 ""), constant.TagRouterRuleSuffix}, ""), config.RouterConfig{
+               
p.routerConfigs.Store(strings.Join([]string{consumerUrl.GetParam(constant.ApplicationKey,
 ""), constant.TagRouterRuleSuffix}, ""), global.RouterConfig{
                        Key:     consumerUrl.Service() + 
constant.TagRouterRuleSuffix,
                        Force:   falsePointer,
                        Enabled: truePointer,
                        Valid:   truePointer,
-                       Tags: []config.Tag{{
+                       Tags: []global.Tag{{
                                Name:      "tag",
                                Addresses: []string{"192.168.0.3:20000"},
                        }},
@@ -199,12 +199,12 @@ func TestRouter(t *testing.T) {
        t.Run("dynamicTag_emptyAddress_requestHasTag", func(t *testing.T) {
                p, err := NewTagPriorityRouter()
                assert.Nil(t, err)
-               
p.routerConfigs.Store(consumerUrl.Service()+constant.TagRouterRuleSuffix, 
config.RouterConfig{
+               
p.routerConfigs.Store(consumerUrl.Service()+constant.TagRouterRuleSuffix, 
global.RouterConfig{
                        Key:     consumerUrl.Service() + 
constant.TagRouterRuleSuffix,
                        Force:   falsePointer,
                        Enabled: truePointer,
                        Valid:   truePointer,
-                       Tags: []config.Tag{{
+                       Tags: []global.Tag{{
                                Name: "tag",
                        }},
                })
@@ -223,12 +223,12 @@ func TestRouter(t *testing.T) {
        t.Run("dynamicTag_address_requestHasTag", func(t *testing.T) {
                p, err := NewTagPriorityRouter()
                assert.Nil(t, err)
-               
p.routerConfigs.Store(strings.Join([]string{consumerUrl.GetParam(constant.ApplicationKey,
 ""), constant.TagRouterRuleSuffix}, ""), config.RouterConfig{
+               
p.routerConfigs.Store(strings.Join([]string{consumerUrl.GetParam(constant.ApplicationKey,
 ""), constant.TagRouterRuleSuffix}, ""), global.RouterConfig{
                        Key:     consumerUrl.Service() + 
constant.TagRouterRuleSuffix,
                        Force:   falsePointer,
                        Enabled: truePointer,
                        Valid:   truePointer,
-                       Tags: []config.Tag{{
+                       Tags: []global.Tag{{
                                Name:      "tag",
                                Addresses: []string{"192.168.0.3:20000"},
                        }},
@@ -248,12 +248,12 @@ func TestRouter(t *testing.T) {
        t.Run("dynamicTag_twoAddress_requestHasTag", func(t *testing.T) {
                p, err := NewTagPriorityRouter()
                assert.Nil(t, err)
-               
p.routerConfigs.Store(strings.Join([]string{consumerUrl.GetParam(constant.ApplicationKey,
 ""), constant.TagRouterRuleSuffix}, ""), config.RouterConfig{
+               
p.routerConfigs.Store(strings.Join([]string{consumerUrl.GetParam(constant.ApplicationKey,
 ""), constant.TagRouterRuleSuffix}, ""), global.RouterConfig{
                        Key:     consumerUrl.Service() + 
constant.TagRouterRuleSuffix,
                        Force:   falsePointer,
                        Enabled: truePointer,
                        Valid:   truePointer,
-                       Tags: []config.Tag{{
+                       Tags: []global.Tag{{
                                Name:      "tag",
                                Addresses: []string{"192.168.0.1:20000", 
"192.168.0.3:20000"},
                        }},
@@ -273,12 +273,12 @@ func TestRouter(t *testing.T) {
        t.Run("dynamicTag_addressNotMatch_requestHasTag", func(t *testing.T) {
                p, err := NewTagPriorityRouter()
                assert.Nil(t, err)
-               
p.routerConfigs.Store(consumerUrl.Service()+constant.TagRouterRuleSuffix, 
config.RouterConfig{
+               
p.routerConfigs.Store(consumerUrl.Service()+constant.TagRouterRuleSuffix, 
global.RouterConfig{
                        Key:     consumerUrl.Service() + 
constant.TagRouterRuleSuffix,
                        Force:   falsePointer,
                        Enabled: truePointer,
                        Valid:   truePointer,
-                       Tags: []config.Tag{{
+                       Tags: []global.Tag{{
                                Name:      "tag",
                                Addresses: []string{"192.168.0.4:20000"},
                        }},
@@ -298,12 +298,12 @@ func TestRouter(t *testing.T) {
        t.Run("dynamicTag_notValid", func(t *testing.T) {
                p, err := NewTagPriorityRouter()
                assert.Nil(t, err)
-               
p.routerConfigs.Store(consumerUrl.Service()+constant.TagRouterRuleSuffix, 
config.RouterConfig{
+               
p.routerConfigs.Store(consumerUrl.Service()+constant.TagRouterRuleSuffix, 
global.RouterConfig{
                        Key:     consumerUrl.Service() + 
constant.TagRouterRuleSuffix,
                        Force:   falsePointer,
                        Enabled: truePointer,
                        Valid:   falsePointer,
-                       Tags: []config.Tag{{
+                       Tags: []global.Tag{{
                                Name:      "tag",
                                Addresses: []string{"192.168.0.1:20000", 
"192.168.0.3:20000"},
                        }},
@@ -367,7 +367,7 @@ tags:
                p.Notify(invokerList)
                value, ok := 
p.routerConfigs.Load(url1.GetParam(constant.ApplicationKey, "") + 
constant.TagRouterRuleSuffix)
                assert.True(t, ok)
-               routerCfg := value.(config.RouterConfig)
+               routerCfg := value.(global.RouterConfig)
                assert.True(t, routerCfg.Key == 
"org.apache.dubbo.UserProvider.Test")
                assert.True(t, len(routerCfg.Tags) == 2)
                assert.True(t, *routerCfg.Enabled)
diff --git a/common/constant/key.go b/common/constant/key.go
index 3740e7445..bf61b1a32 100644
--- a/common/constant/key.go
+++ b/common/constant/key.go
@@ -70,8 +70,9 @@ const (
        // TODO: remove IDLMode after old triple removed
        IDLMode = "IDL-mode"
 
-       TripleConfigKey   = "triple-config"
-       ConsumerConfigKey = "consumer-config"
+       TripleConfigKey     = "triple-config"
+       ConsumerConfigKey   = "consumer-config"
+       RegistriesConfigKey = "registries-config"
 )
 
 // TODO: remove this after old triple removed
diff --git a/global/registry_config.go b/global/registry_config.go
index 20f89cc14..8b5ebac57 100644
--- a/global/registry_config.go
+++ b/global/registry_config.go
@@ -48,6 +48,23 @@ func DefaultRegistryConfig() *RegistryConfig {
        return &RegistryConfig{UseAsMetaReport: "true", UseAsConfigCenter: 
"true", Timeout: "5s", TTL: "15m"}
 }
 
+// DefaultRegistriesConfig returns an empty map for registries configuration
+func DefaultRegistriesConfig() map[string]*RegistryConfig {
+       return make(map[string]*RegistryConfig)
+}
+
+// CloneRegistriesConfig clones a map of RegistryConfig
+func CloneRegistriesConfig(regs map[string]*RegistryConfig) 
map[string]*RegistryConfig {
+       if regs == nil {
+               return nil
+       }
+       cloned := make(map[string]*RegistryConfig, len(regs))
+       for k, v := range regs {
+               cloned[k] = v.Clone()
+       }
+       return cloned
+}
+
 // Clone a new RegistryConfig
 func (c *RegistryConfig) Clone() *RegistryConfig {
        if c == nil {
diff --git a/global/router_config.go b/global/router_config.go
new file mode 100644
index 000000000..9b161b5eb
--- /dev/null
+++ b/global/router_config.go
@@ -0,0 +1,134 @@
+/*
+ * 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 global
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common"
+)
+
+type RouterConfig struct {
+       Scope      string   `validate:"required" yaml:"scope" 
json:"scope,omitempty" property:"scope"`
+       Key        string   `validate:"required" yaml:"key" 
json:"key,omitempty" property:"key"`
+       Force      *bool    `default:"false" yaml:"force" 
json:"force,omitempty" property:"force"`
+       Runtime    *bool    `default:"false" yaml:"runtime" 
json:"runtime,omitempty" property:"runtime"`
+       Enabled    *bool    `default:"true" yaml:"enabled" 
json:"enabled,omitempty" property:"enabled"`
+       Valid      *bool    `default:"true" yaml:"valid" json:"valid,omitempty" 
property:"valid"`
+       Priority   int      `default:"0" yaml:"priority" 
json:"priority,omitempty" property:"priority"`
+       Conditions []string `yaml:"conditions" json:"conditions,omitempty" 
property:"conditions"`
+       Tags       []Tag    `yaml:"tags" json:"tags,omitempty" property:"tags"`
+       ScriptType string   `yaml:"type" json:"type,omitempty" property:"type"`
+       Script     string   `yaml:"script" json:"script,omitempty" 
property:"script"`
+}
+
+type Tag struct {
+       Name      string               `yaml:"name" json:"name,omitempty" 
property:"name"`
+       Match     []*common.ParamMatch `yaml:"match" json:"match,omitempty" 
property:"match"`
+       Addresses []string             `yaml:"addresses" 
json:"addresses,omitempty" property:"addresses"`
+}
+
+type ConditionRule struct {
+       From ConditionRuleFrom `yaml:"from" json:"from,omitempty" 
property:"from"`
+       To   []ConditionRuleTo `yaml:"to" json:"to,omitempty" property:"to"`
+}
+
+type ConditionRuleFrom struct {
+       Match string `yaml:"match" json:"match,omitempty" property:"match"`
+}
+
+type ConditionRuleTo struct {
+       Match  string `yaml:"match" json:"match,omitempty" property:"match"`
+       Weight int    `default:"100" yaml:"weight" json:"weight,omitempty" 
property:"weight"`
+}
+
+type ConditionRuleDisable struct {
+       Match string `yaml:"match" json:"match,omitempty" property:"match"`
+}
+
+type AffinityAware struct {
+       Key   string `default:"" yaml:"key" json:"key,omitempty" property:"key"`
+       Ratio int32  `default:"0" yaml:"ratio" json:"ratio,omitempty" 
property:"ratio"`
+}
+
+// ConditionRouter -- when RouteConfigVersion == v3.1, decode by this
+type ConditionRouter struct {
+       Scope      string           `validate:"required" yaml:"scope" 
json:"scope,omitempty" property:"scope"` // must be chosen from `service` and 
`application`.
+       Key        string           `validate:"required" yaml:"key" 
json:"key,omitempty" property:"key"`       // specifies which service or 
application the rule body acts on.
+       Force      bool             `default:"false" yaml:"force" 
json:"force,omitempty" property:"force"`
+       Runtime    bool             `default:"false" yaml:"runtime" 
json:"runtime,omitempty" property:"runtime"`
+       Enabled    bool             `default:"true" yaml:"enabled" 
json:"enabled,omitempty" property:"enabled"`
+       Conditions []*ConditionRule `yaml:"conditions" 
json:"conditions,omitempty" property:"conditions"`
+}
+
+// AffinityRouter -- RouteConfigVersion == v3.1
+type AffinityRouter struct {
+       Scope         string        `validate:"required" yaml:"scope" 
json:"scope,omitempty" property:"scope"` // must be chosen from `service` and 
`application`.
+       Key           string        `validate:"required" yaml:"key" 
json:"key,omitempty" property:"key"`       // specifies which service or 
application the rule body acts on.
+       Runtime       bool          `default:"false" yaml:"runtime" 
json:"runtime,omitempty" property:"runtime"`
+       Enabled       bool          `default:"true" yaml:"enabled" 
json:"enabled,omitempty" property:"enabled"`
+       AffinityAware AffinityAware `yaml:"affinityAware" 
json:"affinityAware,omitempty" property:"affinityAware"`
+}
+
+func (c *RouterConfig) Clone() *RouterConfig {
+       if c == nil {
+               return nil
+       }
+
+       var newForce *bool
+       if c.Force != nil {
+               newForce = new(bool)
+               *newForce = *c.Force
+       }
+
+       var newRuntime *bool
+       if c.Runtime != nil {
+               newRuntime = new(bool)
+               *newRuntime = *c.Runtime
+       }
+
+       var newEnabled *bool
+       if c.Enabled != nil {
+               newEnabled = new(bool)
+               *newEnabled = *c.Enabled
+       }
+
+       var newValid *bool
+       if c.Valid != nil {
+               newValid = new(bool)
+               *newValid = *c.Valid
+       }
+
+       newConditions := make([]string, len(c.Conditions))
+       copy(newConditions, c.Conditions)
+
+       newTags := make([]Tag, len(c.Tags))
+       copy(newTags, c.Tags)
+
+       return &RouterConfig{
+               Scope:      c.Scope,
+               Key:        c.Key,
+               Force:      newForce,
+               Runtime:    newRuntime,
+               Enabled:    newEnabled,
+               Valid:      newValid,
+               Priority:   c.Priority,
+               Conditions: newConditions,
+               Tags:       newTags,
+               ScriptType: c.ScriptType,
+               Script:     c.Script,
+       }
+}
diff --git a/options.go b/options.go
index 83c81af4c..46df750b6 100644
--- a/options.go
+++ b/options.go
@@ -66,7 +66,7 @@ func defaultInstanceOptions() *InstanceOptions {
        return &InstanceOptions{
                Application:    global.DefaultApplicationConfig(),
                Protocols:      make(map[string]*global.ProtocolConfig),
-               Registries:     make(map[string]*global.RegistryConfig),
+               Registries:     global.DefaultRegistriesConfig(),
                ConfigCenter:   global.DefaultCenterConfig(),
                MetadataReport: global.DefaultMetadataReportConfig(),
                Provider:       global.DefaultProviderConfig(),
diff --git a/registry/directory/directory.go b/registry/directory/directory.go
index 987e964c9..f2e80705d 100644
--- a/registry/directory/directory.go
+++ b/registry/directory/directory.go
@@ -83,11 +83,51 @@ func NewRegistryDirectory(url *common.URL, registry 
registry.Registry) (director
        }
        logger.Debugf("new RegistryDirectory for service :%s.", url.Key())
 
+       // TODO: Temporary compatibility with old APIs, can be removed later
+
+       // set application if not exist
        if _, ok := url.GetAttribute(constant.ApplicationKey); !ok {
                application := config.GetRootConfig().Application
                if application == nil {
                        defaultAppConfig := global.DefaultApplicationConfig()
                        url.SetAttribute(constant.ApplicationKey, 
defaultAppConfig)
+               } else {
+                       url.SetAttribute(constant.ApplicationKey, application)
+               }
+       }
+       // set registry if not exist
+       if _, ok := url.GetAttribute(constant.RegistriesConfigKey); !ok {
+               configRegistries := config.GetRootConfig().Registries
+               if configRegistries == nil {
+                       defaultRegistryConfig := global.DefaultRegistryConfig()
+                       url.SetAttribute(constant.RegistriesConfigKey, 
map[string]*global.RegistryConfig{
+                               constant.DefaultKey: defaultRegistryConfig,
+                       })
+               } else {
+                       // convert config.RegistryConfig to 
global.RegistryConfig
+                       globalRegistries := 
make(map[string]*global.RegistryConfig, len(configRegistries))
+                       for key, configRegistry := range configRegistries {
+                               globalRegistry := &global.RegistryConfig{
+                                       Protocol:          
configRegistry.Protocol,
+                                       Timeout:           
configRegistry.Timeout,
+                                       Group:             configRegistry.Group,
+                                       Namespace:         
configRegistry.Namespace,
+                                       TTL:               configRegistry.TTL,
+                                       Address:           
configRegistry.Address,
+                                       Username:          
configRegistry.Username,
+                                       Password:          
configRegistry.Password,
+                                       Simplified:        
configRegistry.Simplified,
+                                       Preferred:         
configRegistry.Preferred,
+                                       Zone:              configRegistry.Zone,
+                                       Weight:            
configRegistry.Weight,
+                                       Params:            
configRegistry.Params,
+                                       RegistryType:      
configRegistry.RegistryType,
+                                       UseAsMetaReport:   
configRegistry.UseAsMetaReport,
+                                       UseAsConfigCenter: 
configRegistry.UseAsConfigCenter,
+                               }
+                               globalRegistries[key] = globalRegistry
+                       }
+                       url.SetAttribute(constant.RegistriesConfigKey, 
globalRegistries)
                }
        }
 

Reply via email to