//org.apache.dubbo.config.ServiceConfig#doExportUrlsFor1ProtocolprivatevoiddoExportUrlsFor1Protocol(ProtocolConfig protocolConfig,List<URL> registryURLs){String name = protocolConfig.getName();if(StringUtils.isEmpty(name)){
name = DUBBO;}Map<String,String> map =newHashMap<String,String>();
map.put(SIDE_KEY, PROVIDER_SIDE);ServiceConfig.appendRuntimeParameters(map);AbstractConfig.appendParameters(map,getMetrics());AbstractConfig.appendParameters(map,getApplication());AbstractConfig.appendParameters(map,getModule());// remove 'default.' prefix for configs from ProviderConfig// appendParameters(map, provider, Constants.DEFAULT_KEY);AbstractConfig.appendParameters(map, provider);AbstractConfig.appendParameters(map, protocolConfig);AbstractConfig.appendParameters(map,this);MetadataReportConfig metadataReportConfig =getMetadataReportConfig();if(metadataReportConfig !=null&& metadataReportConfig.isValid()){
map.putIfAbsent(METADATA_KEY, REMOTE_METADATA_STORAGE_TYPE);}if(CollectionUtils.isNotEmpty(getMethods())){for(MethodConfig method :getMethods()){AbstractConfig.appendParameters(map, method, method.getName());String retryKey = method.getName()+".retry";if(map.containsKey(retryKey)){String retryValue = map.remove(retryKey);if("false".equals(retryValue)){
map.put(method.getName()+".retries","0");}}List<ArgumentConfig> arguments = method.getArguments();if(CollectionUtils.isNotEmpty(arguments)){for(ArgumentConfig argument : arguments){// convert argument typeif(argument.getType()!=null&& argument.getType().length()>0){Method[] methods = interfaceClass.getMethods();// visit all methodsif(methods.length >0){for(int i =0; i < methods.length; i++){String methodName = methods[i].getName();// target the method, and get its signatureif(methodName.equals(method.getName())){Class<?>[] argtypes = methods[i].getParameterTypes();// one callback in the methodif(argument.getIndex()!=-1){if(argtypes[argument.getIndex()].getName().equals(argument.getType())){AbstractConfig.appendParameters(map, argument, method.getName()+"."+ argument.getIndex());}else{thrownewIllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :"+ argument.getIndex()+", type:"+ argument.getType());}}else{// multiple callbacks in the methodfor(int j =0; j < argtypes.length; j++){Class<?> argclazz = argtypes[j];if(argclazz.getName().equals(argument.getType())){AbstractConfig.appendParameters(map, argument, method.getName()+"."+ j);if(argument.getIndex()!=-1&& argument.getIndex()!= j){thrownewIllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :"+ argument.getIndex()+", type:"+ argument.getType());}}}}}}}}elseif(argument.getIndex()!=-1){AbstractConfig.appendParameters(map, argument, method.getName()+"."+ argument.getIndex());}else{thrownewIllegalArgumentException("Argument config must set index or type attribute.eg: <dubbo:argument index='0' .../> or <dubbo:argument type=xxx .../>");}}}}// end of methods for}if(ProtocolUtils.isGeneric(generic)){
map.put(GENERIC_KEY, generic);
map.put(METHODS_KEY, ANY_VALUE);}else{String revision =Version.getVersion(interfaceClass, version);if(revision !=null&& revision.length()>0){
map.put(REVISION_KEY, revision);}String[] methods =Wrapper.getWrapper(interfaceClass).getMethodNames();if(methods.length ==0){
logger.warn("No method found in service interface "+ interfaceClass.getName());
map.put(METHODS_KEY, ANY_VALUE);}else{
map.put(METHODS_KEY,StringUtils.join(newHashSet<String>(Arrays.asList(methods)),","));}}/**
* Here the token value configured by the provider is used to assign the value to ServiceConfig#token
*/if(ConfigUtils.isEmpty(token)&& provider !=null){
token = provider.getToken();}if(!ConfigUtils.isEmpty(token)){if(ConfigUtils.isDefault(token)){
map.put(TOKEN_KEY, UUID.randomUUID().toString());}else{
map.put(TOKEN_KEY, token);}}//init serviceMetadata attachments
serviceMetadata.getAttachments().putAll(map);// export serviceString host =findConfigedHosts(protocolConfig, registryURLs, map);Integer port =findConfigedPorts(protocolConfig, name, map);URL url =newURL(name, host, port,getContextPath(protocolConfig).map(p -> p +"/"+ path).orElse(path), map);// You can customize Configurator to append extra parametersif(ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class).hasExtension(url.getProtocol())){
url =ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class).getExtension(url.getProtocol()).getConfigurator(url).configure(url);}String scope = url.getParameter(SCOPE_KEY);// don't export when none is configuredif(!SCOPE_NONE.equalsIgnoreCase(scope)){// export to local if the config is not remote (export to remote only when config is remote)if(!SCOPE_REMOTE.equalsIgnoreCase(scope)){exportLocal(url);}// export to remote if the config is not local (export to local only when config is local)if(!SCOPE_LOCAL.equalsIgnoreCase(scope)){if(CollectionUtils.isNotEmpty(registryURLs)){for(URL registryURL : registryURLs){//if protocol is only injvm ,not registerif(LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())){continue;}
url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY));URL monitorUrl =ConfigValidationUtils.loadMonitor(this, registryURL);if(monitorUrl !=null){
url = url.addParameterAndEncoded(MONITOR_KEY, monitorUrl.toFullString());}if(logger.isInfoEnabled()){if(url.getParameter(REGISTER_KEY,true)){
logger.info("Register dubbo service "+ interfaceClass.getName()+" url "+ url.getServiceKey()+" to registry "+ registryURL.getAddress());}else{
logger.info("Export dubbo service "+ interfaceClass.getName()+" to url "+ url.getServiceKey());}}// For providers, this is used to enable custom proxy to generate invokerString proxy = url.getParameter(PROXY_KEY);if(StringUtils.isNotEmpty(proxy)){
registryURL = registryURL.addParameter(PROXY_KEY, proxy);}Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref,(Class) interfaceClass, registryURL.putAttribute(EXPORT_KEY, url));DelegateProviderMetaDataInvoker wrapperInvoker =newDelegateProviderMetaDataInvoker(invoker,this);//1、执行到此处,PROTOCOL = QosProtocolWrapper.classExporter<?> exporter = PROTOCOL.export(wrapperInvoker);
exporters.add(exporter);}}else{if(logger.isInfoEnabled()){
logger.info("Export dubbo service "+ interfaceClass.getName()+" to url "+ url);}if(MetadataService.class.getName().equals(url.getServiceInterface())){MetadataUtils.saveMetadataURL(url);}Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref,(Class) interfaceClass, url);DelegateProviderMetaDataInvoker wrapperInvoker =newDelegateProviderMetaDataInvoker(invoker,this);Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);
exporters.add(exporter);}MetadataUtils.publishServiceDefinition(url);}}this.urls.add(url);}
@Override//org.apache.dubbo.registry.integration.RegistryProtocol#exportpublic<T>Exporter<T>export(finalInvoker<T> originInvoker)throwsRpcException{URL registryUrl =getRegistryUrl(originInvoker);// url to export locallyURL providerUrl =getProviderUrl(originInvoker);// Subscribe the override data// FIXME When the provider subscribes, it will affect the scene : a certain JVM exposes the service and call// the same service. Because the subscribed is cached key with the name of the service, it causes the// subscription information to cover.finalURL overrideSubscribeUrl =getSubscribedOverrideUrl(providerUrl);finalOverrideListener overrideSubscribeListener =newOverrideListener(overrideSubscribeUrl, originInvoker);
overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
providerUrl =overrideUrlWithConfig(providerUrl, overrideSubscribeListener);//export invoker//5、执行到此处finalExporterChangeableWrapper<T> exporter =doLocalExport(originInvoker, providerUrl);// url to registryfinalRegistry registry =getRegistry(registryUrl);finalURL registeredProviderUrl =getUrlToRegistry(providerUrl, registryUrl);// decide if we need to delay publishboolean register = providerUrl.getParameter(REGISTER_KEY,true);if(register){register(registry, registeredProviderUrl);}// register stated url on provider modelregisterStatedUrl(registryUrl, registeredProviderUrl, register);
exporter.setRegisterUrl(registeredProviderUrl);
exporter.setSubscribeUrl(overrideSubscribeUrl);// Deprecated! Subscribe to override rules in 2.6.x or before.
registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);notifyExport(exporter);//Ensure that a new exporter instance is returned every time exportreturnnewDestroyableExporter<>(exporter);}
//org.apache.dubbo.config.ReferenceConfig#createProxyprivateTcreateProxy(Map<String,String> map){if(shouldJvmRefer(map)){URL url =newURL(LOCAL_PROTOCOL, LOCALHOST_VALUE,0, interfaceClass.getName()).addParameters(map);
invoker = REF_PROTOCOL.refer(interfaceClass, url);if(logger.isInfoEnabled()){
logger.info("Using injvm service "+ interfaceClass.getName());}}else{
urls.clear();if(url !=null&& url.length()>0){// user specified URL, could be peer-to-peer address, or register center's address.String[] us = SEMICOLON_SPLIT_PATTERN.split(url);if(us !=null&& us.length >0){for(String u : us){URL url = URL.valueOf(u);if(StringUtils.isEmpty(url.getPath())){
url = url.setPath(interfaceName);}if(UrlUtils.isRegistry(url)){
urls.add(url.putAttribute(REFER_KEY, map));}else{URL peerURL =ClusterUtils.mergeUrl(url, map);
peerURL = peerURL.putAttribute(PEER_KEY,true);
urls.add(peerURL);}}}}else{// assemble URL from register center's configuration// if protocols not injvm checkRegistryif(!LOCAL_PROTOCOL.equalsIgnoreCase(getProtocol())){checkRegistry();List<URL> us =ConfigValidationUtils.loadRegistries(this,false);if(CollectionUtils.isNotEmpty(us)){for(URL u : us){URL monitorUrl =ConfigValidationUtils.loadMonitor(this, u);if(monitorUrl !=null){
map.put(MONITOR_KEY, URL.encode(monitorUrl.toFullString()));}
urls.add(u.putAttribute(REFER_KEY, map));}}if(urls.isEmpty()){thrownewIllegalStateException("No such any registry to reference "+ interfaceName +" on the consumer "+NetUtils.getLocalHost()+" use dubbo version "+Version.getVersion()+", please config <dubbo:registry address=\"...\" /> to your spring config.");}}}if(urls.size()==1){//1、执行到此处,开始执行refer方法
invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0));}else{List<Invoker<?>> invokers =newArrayList<Invoker<?>>();URL registryURL =null;for(URL url : urls){
invokers.add(REF_PROTOCOL.refer(interfaceClass, url));if(UrlUtils.isRegistry(url)){
registryURL = url;// use last registry url}}if(registryURL !=null){// registry url is available// for multi-subscription scenario, use 'zone-aware' policy by defaultString cluster = registryURL.getParameter(CLUSTER_KEY,ZoneAwareCluster.NAME);// The invoker wrap sequence would be: ZoneAwareClusterInvoker(StaticDirectory) -> FailoverClusterInvoker(RegistryDirectory, routing happens here) -> Invoker
invoker =Cluster.getCluster(cluster,false).join(newStaticDirectory(registryURL, invokers));}else{// not a registry url, must be direct invoke.String cluster =CollectionUtils.isNotEmpty(invokers)?(invokers.get(0).getUrl()!=null? invokers.get(0).getUrl().getParameter(CLUSTER_KEY,ZoneAwareCluster.NAME):Cluster.DEFAULT):Cluster.DEFAULT;
invoker =Cluster.getCluster(cluster).join(newStaticDirectory(invokers));}}}if(logger.isInfoEnabled()){
logger.info("Referred dubbo service "+ interfaceClass.getName());}URL consumerURL =newURL(CONSUMER_PROTOCOL, map.get(REGISTER_IP_KEY),0, map.get(INTERFACE_KEY), map);MetadataUtils.publishServiceDefinition(consumerURL);// create service proxyreturn(T) PROXY_FACTORY.getProxy(invoker,ProtocolUtils.isGeneric(generic));}