dubbo.apache.org/dubbo-go/v3@v3.1.1/registry/directory/directory.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package directory
    19  
    20  import (
    21  	"fmt"
    22  	"net/url"
    23  	"os"
    24  	"sync"
    25  	"time"
    26  )
    27  
    28  import (
    29  	"github.com/dubbogo/gost/log/logger"
    30  
    31  	perrors "github.com/pkg/errors"
    32  )
    33  
    34  import (
    35  	"dubbo.apache.org/dubbo-go/v3/cluster/directory"
    36  	"dubbo.apache.org/dubbo-go/v3/cluster/directory/base"
    37  	"dubbo.apache.org/dubbo-go/v3/cluster/directory/static"
    38  	"dubbo.apache.org/dubbo-go/v3/cluster/router/chain"
    39  	"dubbo.apache.org/dubbo-go/v3/common"
    40  	"dubbo.apache.org/dubbo-go/v3/common/constant"
    41  	"dubbo.apache.org/dubbo-go/v3/common/extension"
    42  	"dubbo.apache.org/dubbo-go/v3/config"
    43  	"dubbo.apache.org/dubbo-go/v3/config_center"
    44  	_ "dubbo.apache.org/dubbo-go/v3/config_center/configurator"
    45  	"dubbo.apache.org/dubbo-go/v3/metrics"
    46  	metricsRegistry "dubbo.apache.org/dubbo-go/v3/metrics/registry"
    47  	"dubbo.apache.org/dubbo-go/v3/protocol"
    48  	"dubbo.apache.org/dubbo-go/v3/protocol/protocolwrapper"
    49  	"dubbo.apache.org/dubbo-go/v3/registry"
    50  	"dubbo.apache.org/dubbo-go/v3/remoting"
    51  )
    52  
    53  func init() {
    54  	extension.SetDefaultRegistryDirectory(NewRegistryDirectory)
    55  	extension.SetDirectory(constant.RegistryProtocol, NewRegistryDirectory)
    56  	extension.SetDirectory(constant.ServiceRegistryProtocol, NewServiceDiscoveryRegistryDirectory)
    57  }
    58  
    59  // RegistryDirectory implementation of Directory:
    60  // Invoker list returned from this Directory's list method have been filtered by Routers
    61  type RegistryDirectory struct {
    62  	*base.Directory
    63  	cacheInvokers                  []protocol.Invoker
    64  	invokersLock                   sync.RWMutex
    65  	serviceType                    string
    66  	registry                       registry.Registry
    67  	cacheInvokersMap               *sync.Map // use sync.map
    68  	consumerURL                    *common.URL
    69  	cacheOriginUrl                 *common.URL
    70  	configurators                  []config_center.Configurator
    71  	consumerConfigurationListener  *consumerConfigurationListener
    72  	referenceConfigurationListener *referenceConfigurationListener
    73  	registerLock                   sync.Mutex // this lock if for register
    74  	SubscribedUrl                  *common.URL
    75  	RegisteredUrl                  *common.URL
    76  }
    77  
    78  // NewRegistryDirectory will create a new RegistryDirectory
    79  func NewRegistryDirectory(url *common.URL, registry registry.Registry) (directory.Directory, error) {
    80  	if url.SubURL == nil {
    81  		return nil, perrors.Errorf("url is invalid, suburl can not be nil")
    82  	}
    83  	logger.Debugf("new RegistryDirectory for service :%s.", url.Key())
    84  	dir := &RegistryDirectory{
    85  		Directory:        base.NewDirectory(url),
    86  		cacheInvokers:    []protocol.Invoker{},
    87  		cacheInvokersMap: &sync.Map{},
    88  		serviceType:      url.SubURL.Service(),
    89  		registry:         registry,
    90  	}
    91  
    92  	dir.consumerURL = dir.getConsumerUrl(url.SubURL)
    93  
    94  	if routerChain, err := chain.NewRouterChain(); err == nil {
    95  		dir.Directory.SetRouterChain(routerChain)
    96  	} else {
    97  		logger.Warnf("fail to create router chain with url: %s, err is: %v", url.SubURL, err)
    98  	}
    99  
   100  	dir.consumerConfigurationListener = newConsumerConfigurationListener(dir)
   101  	dir.consumerConfigurationListener.addNotifyListener(dir)
   102  	dir.referenceConfigurationListener = newReferenceConfigurationListener(dir, url)
   103  
   104  	if err := dir.registry.LoadSubscribeInstances(url.SubURL, dir); err != nil {
   105  		return nil, err
   106  	}
   107  	metrics.Publish(metricsRegistry.NewDirectoryEvent(metricsRegistry.NumAllInc))
   108  	return dir, nil
   109  }
   110  
   111  // subscribe from registry
   112  func (dir *RegistryDirectory) Subscribe(url *common.URL) error {
   113  	logger.Infof("Start subscribing for service :%s with a new go routine.", url.Key())
   114  
   115  	go func() {
   116  		dir.SubscribedUrl = url
   117  		if err := dir.registry.Subscribe(url, dir); err != nil {
   118  			logger.Error("registry.Subscribe(url:%v, dir:%v) = error:%v", url, dir, err)
   119  		}
   120  
   121  		urlToReg := getConsumerUrlToRegistry(url)
   122  		err := dir.registry.Register(urlToReg)
   123  		if err != nil {
   124  			logger.Errorf("consumer service %v register registry %v error, error message is %s",
   125  				url.String(), dir.registry.GetURL().String(), err.Error())
   126  		}
   127  	}()
   128  
   129  	return nil
   130  }
   131  
   132  // Notify monitor changes from registry,and update the cacheServices
   133  func (dir *RegistryDirectory) Notify(event *registry.ServiceEvent) {
   134  	if event == nil {
   135  		return
   136  	}
   137  	start := time.Now()
   138  	dir.refreshInvokers(event)
   139  	metrics.Publish(metricsRegistry.NewNotifyEvent(start))
   140  }
   141  
   142  // NotifyAll notify the events that are complete Service Event List.
   143  // After notify the address, the callback func will be invoked.
   144  func (dir *RegistryDirectory) NotifyAll(events []*registry.ServiceEvent, callback func()) {
   145  	go dir.refreshAllInvokers(events, callback)
   146  }
   147  
   148  // refreshInvokers refreshes service's events.
   149  func (dir *RegistryDirectory) refreshInvokers(event *registry.ServiceEvent) {
   150  	if event != nil {
   151  		logger.Debugf("refresh invokers with %+v", event)
   152  	} else {
   153  		logger.Debug("refresh invokers with nil")
   154  	}
   155  
   156  	var oldInvoker []protocol.Invoker
   157  	if event != nil {
   158  		oldInvoker, _ = dir.cacheInvokerByEvent(event)
   159  	}
   160  	dir.setNewInvokers()
   161  	for _, v := range oldInvoker {
   162  		if v != nil {
   163  			v.Destroy()
   164  		}
   165  	}
   166  }
   167  
   168  // refreshAllInvokers the argument is the complete list of the service events,  we can safely assume any cached invoker
   169  // not in the incoming list can be removed.  The Action of serviceEvent should be EventTypeUpdate or EventTypeAdd.
   170  func (dir *RegistryDirectory) refreshAllInvokers(events []*registry.ServiceEvent, callback func()) {
   171  	var (
   172  		oldInvokers []protocol.Invoker
   173  		addEvents   []*registry.ServiceEvent
   174  	)
   175  	dir.overrideUrl(dir.GetDirectoryUrl())
   176  	referenceUrl := dir.GetDirectoryUrl().SubURL
   177  
   178  	// loop the events to check the Action should be EventTypeUpdate.
   179  	for _, event := range events {
   180  		if event.Action != remoting.EventTypeUpdate && event.Action != remoting.EventTypeAdd {
   181  			panic("Your implements of register center is wrong, " +
   182  				"please check the Action of ServiceEvent should be EventTypeUpdate")
   183  		}
   184  		// Originally it will Merge URL many times, now we just execute once.
   185  		// MergeURL is executed once and put the result into Event. After this, the key will get from Event.Key().
   186  		newUrl := dir.convertUrl(event)
   187  		newUrl = common.MergeURL(newUrl, referenceUrl)
   188  		dir.overrideUrl(newUrl)
   189  		event.Update(newUrl)
   190  	}
   191  	// After notify all addresses, do some callback.
   192  	defer callback()
   193  	func() {
   194  		// this lock is work at batch update of InvokeCache
   195  		dir.registerLock.Lock()
   196  		defer dir.registerLock.Unlock()
   197  		// get need clear invokers from original invoker list
   198  		dir.cacheInvokersMap.Range(func(k, v interface{}) bool {
   199  			if !dir.eventMatched(k.(string), events) {
   200  				// delete unused invoker from cache
   201  				if invoker := dir.uncacheInvokerWithKey(k.(string)); invoker != nil {
   202  					oldInvokers = append(oldInvokers, invoker)
   203  				}
   204  			}
   205  			return true
   206  		})
   207  		// get need add invokers from events
   208  		for _, event := range events {
   209  			// Get the key from Event.Key()
   210  			if _, ok := dir.cacheInvokersMap.Load(event.Key()); !ok {
   211  				addEvents = append(addEvents, event)
   212  			}
   213  		}
   214  		// loop the serviceEvents
   215  		for _, event := range addEvents {
   216  			logger.Debugf("[Registry Directory] registry changed, result{%s}", event)
   217  			if event != nil && event.Service != nil {
   218  				logger.Infof("[Registry Directory] selector add service url{%s}", event.Service.String())
   219  			}
   220  			if event != nil && event.Service != nil && constant.RouterProtocol == event.Service.Protocol {
   221  				dir.configRouters()
   222  			}
   223  			if oldInvoker, _ := dir.doCacheInvoker(event.Service, event); oldInvoker != nil {
   224  				oldInvokers = append(oldInvokers, oldInvoker)
   225  			}
   226  		}
   227  	}()
   228  	dir.setNewInvokers()
   229  	// destroy unused invokers
   230  	for _, invoker := range oldInvokers {
   231  		go invoker.Destroy()
   232  	}
   233  }
   234  
   235  // eventMatched checks if a cached invoker appears in the incoming invoker list, if no, then it is safe to remove.
   236  func (dir *RegistryDirectory) eventMatched(key string, events []*registry.ServiceEvent) bool {
   237  	for _, event := range events {
   238  		if dir.invokerCacheKey(event) == key {
   239  			return true
   240  		}
   241  	}
   242  	return false
   243  }
   244  
   245  // invokerCacheKey generates the key in the cache for a given ServiceEvent.
   246  func (dir *RegistryDirectory) invokerCacheKey(event *registry.ServiceEvent) string {
   247  	// If the url is merged, then return Event.Key() directly.
   248  	if event.Updated() {
   249  		return event.Key()
   250  	}
   251  	referenceUrl := dir.GetDirectoryUrl().SubURL
   252  	newUrl := common.MergeURL(event.Service, referenceUrl)
   253  	event.Update(newUrl)
   254  	return event.Key()
   255  }
   256  
   257  // setNewInvokers groups the invokers from the cache first, then set the result to both directory and router chain.
   258  func (dir *RegistryDirectory) setNewInvokers() {
   259  	newInvokers := dir.toGroupInvokers()
   260  	dir.invokersLock.Lock()
   261  	defer dir.invokersLock.Unlock()
   262  	dir.cacheInvokers = newInvokers
   263  	dir.RouterChain().SetInvokers(newInvokers)
   264  }
   265  
   266  // cacheInvokerByEvent caches invokers from the service event
   267  func (dir *RegistryDirectory) cacheInvokerByEvent(event *registry.ServiceEvent) ([]protocol.Invoker, error) {
   268  	// judge is override or others
   269  	if event != nil {
   270  
   271  		switch event.Action {
   272  		case remoting.EventTypeAdd, remoting.EventTypeUpdate:
   273  			u := dir.convertUrl(event)
   274  			logger.Infof("[Registry Directory] selector add service url{%s}", event.Service)
   275  			if u != nil && constant.RouterProtocol == u.Protocol {
   276  				dir.configRouters()
   277  			}
   278  			return []protocol.Invoker{dir.cacheInvoker(u, event)}, nil
   279  		case remoting.EventTypeDel:
   280  			logger.Infof("[Registry Directory] selector delete service url{%s}", event.Service)
   281  			return dir.uncacheInvoker(event), nil
   282  		default:
   283  			return nil, fmt.Errorf("illegal event type: %v", event.Action)
   284  		}
   285  	}
   286  	return nil, nil
   287  }
   288  
   289  // configRouters configures dynamic routers into the router chain, but, the current impl is incorrect, see FIXME above.
   290  func (dir *RegistryDirectory) configRouters() {
   291  }
   292  
   293  // convertUrl processes override:// and router://
   294  func (dir *RegistryDirectory) convertUrl(res *registry.ServiceEvent) *common.URL {
   295  	ret := res.Service
   296  	if ret.Protocol == constant.OverrideProtocol || // 1.for override url in 2.6.x
   297  		ret.GetParam(constant.CategoryKey, constant.DefaultCategory) == constant.ConfiguratorsCategory {
   298  		dir.configurators = append(dir.configurators, extension.GetDefaultConfigurator(ret))
   299  		ret = nil
   300  	} else if ret.Protocol == constant.RouterProtocol || // 2.for router
   301  		ret.GetParam(constant.CategoryKey, constant.DefaultCategory) == constant.RouterCategory {
   302  		ret = nil
   303  	}
   304  	return ret
   305  }
   306  
   307  func (dir *RegistryDirectory) toGroupInvokers() []protocol.Invoker {
   308  	groupInvokersMap := make(map[string][]protocol.Invoker)
   309  
   310  	dir.cacheInvokersMap.Range(func(key, value interface{}) bool {
   311  		invoker := value.(protocol.Invoker)
   312  		group := invoker.GetURL().GetParam(constant.GroupKey, "")
   313  		groupInvokersMap[group] = append(groupInvokersMap[group], invoker)
   314  		return true
   315  	})
   316  
   317  	groupInvokersList := make([]protocol.Invoker, 0, len(groupInvokersMap))
   318  	if len(groupInvokersMap) == 1 {
   319  		// len is 1 it means no group setting ,so do not need cluster again
   320  		for _, invokers := range groupInvokersMap {
   321  			groupInvokersList = invokers
   322  		}
   323  	} else {
   324  		for _, invokers := range groupInvokersMap {
   325  			staticDir := static.NewDirectory(invokers)
   326  			clusterKey := dir.GetURL().SubURL.GetParam(constant.ClusterKey, constant.DefaultCluster)
   327  			cluster, err := extension.GetCluster(clusterKey)
   328  			if err != nil {
   329  				panic(err)
   330  			}
   331  			err = staticDir.BuildRouterChain(invokers)
   332  			if err != nil {
   333  				logger.Error(err)
   334  				continue
   335  			}
   336  			groupInvokersList = append(groupInvokersList, cluster.Join(staticDir))
   337  		}
   338  	}
   339  
   340  	return groupInvokersList
   341  }
   342  
   343  func (dir *RegistryDirectory) uncacheInvokerWithClusterID(clusterID string) []protocol.Invoker {
   344  	logger.Debugf("All service will be deleted in cache invokers with clusterID %s!", clusterID)
   345  	invokerKeys := make([]string, 0)
   346  	dir.cacheInvokersMap.Range(func(key, cacheInvoker interface{}) bool {
   347  		if cacheInvoker.(protocol.Invoker).GetURL().GetParam(constant.MeshClusterIDKey, "") == clusterID {
   348  			invokerKeys = append(invokerKeys, key.(string))
   349  		}
   350  		return true
   351  	})
   352  	uncachedInvokers := make([]protocol.Invoker, 0)
   353  	for _, v := range invokerKeys {
   354  		uncachedInvokers = append(uncachedInvokers, dir.uncacheInvokerWithKey(v))
   355  	}
   356  	return uncachedInvokers
   357  }
   358  
   359  // uncacheInvoker will return abandoned Invoker, if no Invoker to be abandoned, return nil
   360  func (dir *RegistryDirectory) uncacheInvoker(event *registry.ServiceEvent) []protocol.Invoker {
   361  	defer metrics.Publish(metricsRegistry.NewDirectoryEvent(metricsRegistry.NumDisableTotal))
   362  	if clusterID := event.Service.GetParam(constant.MeshClusterIDKey, ""); event.Service.Location == constant.MeshAnyAddrMatcher && clusterID != "" {
   363  		dir.uncacheInvokerWithClusterID(clusterID)
   364  	}
   365  	return []protocol.Invoker{dir.uncacheInvokerWithKey(event.Key())}
   366  }
   367  
   368  func (dir *RegistryDirectory) uncacheInvokerWithKey(key string) protocol.Invoker {
   369  	logger.Debugf("service will be deleted in cache invokers: invokers key is  %s!", key)
   370  	protocol.RemoveUrlKeyUnhealthyStatus(key)
   371  	if cacheInvoker, ok := dir.cacheInvokersMap.Load(key); ok {
   372  		dir.cacheInvokersMap.Delete(key)
   373  		return cacheInvoker.(protocol.Invoker)
   374  	}
   375  	return nil
   376  }
   377  
   378  // cacheInvoker will return abandoned Invoker,if no Invoker to be abandoned,return nil
   379  func (dir *RegistryDirectory) cacheInvoker(url *common.URL, event *registry.ServiceEvent) protocol.Invoker {
   380  	dir.overrideUrl(dir.GetDirectoryUrl())
   381  	referenceUrl := dir.GetDirectoryUrl().SubURL
   382  
   383  	if url == nil && dir.cacheOriginUrl != nil {
   384  		url = dir.cacheOriginUrl
   385  	} else {
   386  		dir.cacheOriginUrl = url
   387  	}
   388  	if url == nil {
   389  		logger.Error("URL is nil ,pls check if service url is subscribe successfully!")
   390  		return nil
   391  	}
   392  	// check the url's protocol is equal to the protocol which is configured in reference config or referenceUrl is not care about protocol
   393  	if url.Protocol == referenceUrl.Protocol || referenceUrl.Protocol == "" {
   394  		newUrl := common.MergeURL(url, referenceUrl)
   395  		dir.overrideUrl(newUrl)
   396  		event.Update(newUrl)
   397  		if v, ok := dir.doCacheInvoker(newUrl, event); ok {
   398  			return v
   399  		}
   400  	}
   401  	return nil
   402  }
   403  
   404  func (dir *RegistryDirectory) doCacheInvoker(newUrl *common.URL, event *registry.ServiceEvent) (protocol.Invoker, bool) {
   405  	key := event.Key()
   406  	if cacheInvoker, ok := dir.cacheInvokersMap.Load(key); !ok {
   407  		logger.Debugf("service will be added in cache invokers: invokers url is  %s!", newUrl)
   408  		newInvoker := extension.GetProtocol(protocolwrapper.FILTER).Refer(newUrl)
   409  		if newInvoker != nil {
   410  			dir.cacheInvokersMap.Store(key, newInvoker)
   411  		} else {
   412  			logger.Warnf("service will be added in cache invokers fail, result is null, invokers url is %+v", newUrl.String())
   413  		}
   414  	} else {
   415  		metrics.Publish(metricsRegistry.NewDirectoryEvent(metricsRegistry.NumValidTotal))
   416  		// if cached invoker has the same URL with the new URL, then no need to re-refer, and no need to destroy
   417  		// the old invoker.
   418  		if common.GetCompareURLEqualFunc()(newUrl, cacheInvoker.(protocol.Invoker).GetURL()) {
   419  			return nil, true
   420  		}
   421  
   422  		logger.Debugf("service will be updated in cache invokers: new invoker url is %s, old invoker url is %s", newUrl, cacheInvoker.(protocol.Invoker).GetURL())
   423  		newInvoker := extension.GetProtocol(protocolwrapper.FILTER).Refer(newUrl)
   424  		if newInvoker != nil {
   425  			dir.cacheInvokersMap.Store(key, newInvoker)
   426  			return cacheInvoker.(protocol.Invoker), true
   427  		} else {
   428  			logger.Warnf("service will be updated in cache invokers fail, result is null, invokers url is %+v", newUrl.String())
   429  		}
   430  	}
   431  	return nil, false
   432  }
   433  
   434  // List selected protocol invokers from the directory
   435  func (dir *RegistryDirectory) List(invocation protocol.Invocation) []protocol.Invoker {
   436  	routerChain := dir.RouterChain()
   437  
   438  	if routerChain == nil {
   439  		dir.invokersLock.RLock()
   440  		defer dir.invokersLock.RUnlock()
   441  		return dir.cacheInvokers
   442  	}
   443  	return routerChain.Route(dir.consumerURL, invocation)
   444  }
   445  
   446  // IsAvailable  whether the directory is available
   447  func (dir *RegistryDirectory) IsAvailable() bool {
   448  	if dir.Directory.IsDestroyed() {
   449  		return false
   450  	}
   451  
   452  	for _, ivk := range dir.cacheInvokers {
   453  		if ivk.IsAvailable() {
   454  			return true
   455  		}
   456  	}
   457  	metrics.Publish(metricsRegistry.NewDirectoryEvent(metricsRegistry.NumToReconnectTotal))
   458  	return false
   459  }
   460  
   461  // Destroy method
   462  func (dir *RegistryDirectory) Destroy() {
   463  	// TODO:unregister & unsubscribe
   464  	dir.Directory.DoDestroy(func() {
   465  		if dir.RegisteredUrl != nil {
   466  			err := dir.registry.UnRegister(dir.RegisteredUrl)
   467  			if err != nil {
   468  				logger.Warnf("Unregister consumer url failed, %s", dir.RegisteredUrl.String(), err)
   469  			}
   470  		}
   471  
   472  		if dir.SubscribedUrl != nil {
   473  			err := dir.registry.UnSubscribe(dir.SubscribedUrl, dir)
   474  			if err != nil {
   475  				logger.Warnf("Unsubscribe consumer url failed, %s", dir.RegisteredUrl.String(), err)
   476  			}
   477  		}
   478  
   479  		invokers := dir.cacheInvokers
   480  		dir.cacheInvokers = []protocol.Invoker{}
   481  		for _, ivk := range invokers {
   482  			ivk.Destroy()
   483  		}
   484  	})
   485  	metrics.Publish(metricsRegistry.NewDirectoryEvent(metricsRegistry.NumAllDec))
   486  }
   487  
   488  func (dir *RegistryDirectory) overrideUrl(targetUrl *common.URL) {
   489  	doOverrideUrl(dir.configurators, targetUrl)
   490  	doOverrideUrl(dir.consumerConfigurationListener.Configurators(), targetUrl)
   491  	doOverrideUrl(dir.referenceConfigurationListener.Configurators(), targetUrl)
   492  }
   493  
   494  func (dir *RegistryDirectory) getConsumerUrl(c *common.URL) *common.URL {
   495  	processID := fmt.Sprintf("%d", os.Getpid())
   496  	localIP := common.GetLocalIp()
   497  
   498  	params := url.Values{}
   499  	c.RangeParams(func(key, value string) bool {
   500  		params.Add(key, value)
   501  		return true
   502  	})
   503  
   504  	params.Add("pid", processID)
   505  	params.Add("ip", localIP)
   506  	params.Add("protocol", c.Protocol)
   507  
   508  	return common.NewURLWithOptions(common.WithProtocol("consumer"), common.WithIp(localIP), common.WithPath(c.Path),
   509  		common.WithParams(params))
   510  }
   511  
   512  func doOverrideUrl(configurators []config_center.Configurator, targetUrl *common.URL) {
   513  	for _, v := range configurators {
   514  		v.Configure(targetUrl)
   515  	}
   516  }
   517  
   518  type referenceConfigurationListener struct {
   519  	registry.BaseConfigurationListener
   520  	directory *RegistryDirectory
   521  	url       *common.URL
   522  }
   523  
   524  func newReferenceConfigurationListener(dir *RegistryDirectory, url *common.URL) *referenceConfigurationListener {
   525  	listener := &referenceConfigurationListener{directory: dir, url: url}
   526  	listener.InitWith(
   527  		url.ColonSeparatedKey()+constant.ConfiguratorSuffix,
   528  		listener,
   529  		extension.GetDefaultConfiguratorFunc(),
   530  	)
   531  	return listener
   532  }
   533  
   534  // Process handle events and update Invokers
   535  func (l *referenceConfigurationListener) Process(event *config_center.ConfigChangeEvent) {
   536  	l.BaseConfigurationListener.Process(event)
   537  	// FIXME: this doesn't trigger dir.overrideUrl()
   538  	l.directory.refreshInvokers(nil)
   539  }
   540  
   541  type consumerConfigurationListener struct {
   542  	registry.BaseConfigurationListener
   543  	listeners []registry.NotifyListener
   544  	directory *RegistryDirectory
   545  }
   546  
   547  func newConsumerConfigurationListener(dir *RegistryDirectory) *consumerConfigurationListener {
   548  	listener := &consumerConfigurationListener{directory: dir}
   549  	application := config.GetRootConfig().Application
   550  	listener.InitWith(
   551  		application.Name+constant.ConfiguratorSuffix,
   552  		listener,
   553  		extension.GetDefaultConfiguratorFunc(),
   554  	)
   555  	return listener
   556  }
   557  
   558  func (l *consumerConfigurationListener) addNotifyListener(listener registry.NotifyListener) {
   559  	l.listeners = append(l.listeners, listener)
   560  }
   561  
   562  // Process handles events from Configuration Center and update Invokers
   563  func (l *consumerConfigurationListener) Process(event *config_center.ConfigChangeEvent) {
   564  	l.BaseConfigurationListener.Process(event)
   565  	// FIXME: this doesn't trigger dir.overrideUrl()
   566  	l.directory.refreshInvokers(nil)
   567  }
   568  
   569  // ServiceDiscoveryRegistryDirectory implementation of Directory:
   570  // Invoker list returned from this Directory's list method have been filtered by Routers
   571  type ServiceDiscoveryRegistryDirectory struct {
   572  	*base.Directory
   573  	*RegistryDirectory
   574  }
   575  
   576  // NewServiceDiscoveryRegistryDirectory will create a new ServiceDiscoveryRegistryDirectory
   577  func NewServiceDiscoveryRegistryDirectory(url *common.URL, registry registry.Registry) (directory.Directory, error) {
   578  	dic, err := NewRegistryDirectory(url, registry)
   579  	registryDirectory, _ := dic.(*RegistryDirectory)
   580  	return &ServiceDiscoveryRegistryDirectory{
   581  		Directory:         registryDirectory.Directory,
   582  		RegistryDirectory: registryDirectory,
   583  	}, err
   584  }
   585  
   586  // Subscribe do subscribe from registry
   587  func (dir *ServiceDiscoveryRegistryDirectory) Subscribe(url *common.URL) error {
   588  	if err := dir.registry.Subscribe(url, dir); err != nil {
   589  		logger.Error("registry.Subscribe(url:%v, dir:%v) = error:%v", url, dir, err)
   590  		return err
   591  	}
   592  
   593  	urlToReg := getConsumerUrlToRegistry(url)
   594  	err := dir.RegistryDirectory.registry.Register(urlToReg)
   595  	if err != nil {
   596  		logger.Errorf("consumer service %v register registry %v error, error message is %s",
   597  			url.String(), dir.registry.GetURL().String(), err.Error())
   598  		return err
   599  	}
   600  	return nil
   601  }
   602  
   603  // List selected protocol invokers from the directory
   604  func (dir *ServiceDiscoveryRegistryDirectory) List(invocation protocol.Invocation) []protocol.Invoker {
   605  	return dir.RegistryDirectory.List(invocation)
   606  }
   607  
   608  func getConsumerUrlToRegistry(url *common.URL) *common.URL {
   609  	// if developer define registry port and ip, use it first.
   610  	if ipToRegistry := os.Getenv(constant.DubboIpToRegistryKey); len(ipToRegistry) > 0 {
   611  		url.Ip = ipToRegistry
   612  	} else {
   613  		url.Ip = common.GetLocalIp()
   614  	}
   615  	if portToRegistry := os.Getenv(constant.DubboPortToRegistryKey); len(portToRegistry) > 0 {
   616  		url.Port = portToRegistry
   617  	}
   618  	return url
   619  }