in config/reference_config.go [169:301]
func (rc *ReferenceConfig) Refer(srv any) {
// 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 := serviceURL.MergeURL(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))
}
}
// 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)
}
}