(五)禁用启用提供者

xiaoxiao2021-02-28  60

##禁用启用提供者

禁用配置

管理后台:dubbo-admin,或叫治理中心 在dubbo的治理中心,动态配置上配置 disabled=true 此外,enabled=true覆盖规则是否生效,可不填,缺省生效。 接口的动态配置 注册到zookeeper 的节点/dubbo/接口全包名/configurators override://192.168.204.79:20880/lam.dubbo.api.LoginService?category=configurators&disabled=true&dynamic=false&enabled=true, override://192.168.56.1/lam.dubbo.api.LoginService?category=configurators&dynamic=false&enabled=true&mock=fail:return+null 并通知 提供者的订阅者,比如消费者 05-05 11:23:10:INFO(422) com.alibaba.dubbo.registry.zookeeper.ZookeeperRegistry -  [DUBBO] Notify urls for subscribe url provider://192.168.56.1:20880/lam.dubbo.api.LoginService?anyhost=true&application=lam-dubbo-provider&category=configurators&charset=UTF-8&check=false&default.accepts=0&default.actives=0&default.buffer=8192&default.charset=UTF-8&default.client=netty&default.cluster=failover&default.connections=0&default.executes=0&default.loadbalance=random&default.owner=sky&default.payload=88388608&default.proxy=javassist&default.retries=2&default.serialization=hessian2&default.server=netty&default.threadpool=fixed&default.threads=100&default.timeout=1000&default.token=false&default.weight=100&dispatcher=all&dubbo=2.5.3&interface=lam.dubbo.api.LoginService&loadbalance=roundrobin&methods=logout,login&owner=skylin&pid=10724&serialization=hessian2&side=provider&threadpool=fixed&threads=100×tamp=1493885611668&transporter=netty, urls: [override://192.168.204.79:20880/lam.dubbo.api.LoginService?category=configurators&disabled=true&dynamic=false&enabled=true, override://192.168.56.1/lam.dubbo.api.LoginService?category=configurators&dynamic=false&enabled=true&mock=fail:return+null], dubbo version: 2.5.3, current host: 127.0.0.1  

源码原理

提供者的订阅者,会刷新本地的提供者列表,代码如下:

private void refreshInvoker(List<URL> invokerUrls){ if (invokerUrls != null && invokerUrls.size() == 1 && invokerUrls.get(0) != null && Constants.EMPTY_PROTOCOL.equals(invokerUrls.get(0).getProtocol())) { this.forbidden = true; // 禁止访问 this.methodInvokerMap = null; // 置空列表 destroyAllInvokers(); // 关闭所有Invoker } else { this.forbidden = false; // 允许访问 Map<String, Invoker<T>> oldUrlInvokerMap = this.urlInvokerMap; // local reference if (invokerUrls.size() == 0 && this.cachedInvokerUrls != null){ invokerUrls.addAll(this.cachedInvokerUrls); } else { this.cachedInvokerUrls = new HashSet<URL>(); this.cachedInvokerUrls.addAll(invokerUrls);//缓存invokerUrls列表,便于交叉对比 } if (invokerUrls.size() ==0 ){ return; } Map<String, Invoker<T>> newUrlInvokerMap = toInvokers(invokerUrls) ;// 将URL列表转成Invoker列表 //1处 Map<String, List<Invoker<T>>> newMethodInvokerMap = toMethodInvokers(newUrlInvokerMap); // 换方法名映射Invoker列表 //11处 // state change //如果计算错误,则不进行处理. if (newUrlInvokerMap == null || newUrlInvokerMap.size() == 0 ){ logger.error(new IllegalStateException("urls to invokers error .invokerUrls.size :"+invokerUrls.size() + ", invoker.size :0. urls :"+invokerUrls.toString())); return ; } this.methodInvokerMap = multiGroup ? toMergeMethodInvokerMap(newMethodInvokerMap) : newMethodInvokerMap; this.urlInvokerMap = newUrlInvokerMap; try{ destroyUnusedInvokers(oldUrlInvokerMap,newUrlInvokerMap); // 关闭未使用的Invoker }catch (Exception e) { logger.warn("destroyUnusedInvokers error. ", e); } } }

在代码1处,toInvokers方法将url转成调用者Invoker的列表,这里会有服务禁用、启用功能的实现,看下面方法的实现代码: 在代码11处,toMethodInvokers方法将调用者Invoker的列表,转成方法名映射Invoker的列表,这里会有路由功能的实现,介绍完禁用服务功能,下面会介绍路由功能。

/** * 将urls转成invokers,如果url已经被refer过,不再重新引用。 */ private Map<String, Invoker<T>> toInvokers(List<URL> urls) { Map<String, Invoker<T>> newUrlInvokerMap = new HashMap<String, Invoker<T>>(); if(urls == null || urls.size() == 0){ return newUrlInvokerMap; } Set<String> keys = new HashSet<String>(); String queryProtocols = this.queryMap.get(Constants.PROTOCOL_KEY); for (URL providerUrl : urls) { //如果reference端配置了protocol,则只选择匹配的protocol if (queryProtocols != null && queryProtocols.length() >0) { boolean accept = false; String[] acceptProtocols = queryProtocols.split(","); for (String acceptProtocol : acceptProtocols) { if (providerUrl.getProtocol().equals(acceptProtocol)) { accept = true; break; } } if (!accept) { continue; } } if (Constants.EMPTY_PROTOCOL.equals(providerUrl.getProtocol())) { continue; } if (! ExtensionLoader.getExtensionLoader(Protocol.class).hasExtension(providerUrl.getProtocol())) { logger.error(new IllegalStateException("Unsupported protocol " + providerUrl.getProtocol() + " in notified url: " + providerUrl + " from registry " + getUrl().getAddress() + " to consumer " + NetUtils.getLocalHost() + ", supported protocol: "+ExtensionLoader.getExtensionLoader(Protocol.class).getSupportedExtensions())); continue; } URL url = mergeUrl(providerUrl); String key = url.toFullString(); // URL参数是排序的 if (keys.contains(key)) { // 重复URL continue; } keys.add(key); // 缓存key为没有合并消费端参数的URL,不管消费端如何合并参数,如果服务端URL发生变化,则重新refer Map<String, Invoker<T>> localUrlInvokerMap = this.urlInvokerMap; // local reference Invoker<T> invoker = localUrlInvokerMap == null ? null : localUrlInvokerMap.get(key); if (invoker == null) { // 缓存中没有,重新refer try { boolean enabled = true; if (url.hasParameter(Constants.DISABLED_KEY)) { //2处 enabled = ! url.getParameter(Constants.DISABLED_KEY, false); } else { enabled = url.getParameter(Constants.ENABLED_KEY, true); } if (enabled) { invoker = new InvokerDelegete<T>(protocol.refer(serviceType, url), url, providerUrl); } } catch (Throwable t) { logger.error("Failed to refer invoker for interface:"+serviceType+",url:("+url+")" + t.getMessage(), t); } if (invoker != null) { // 将新的引用放入缓存 newUrlInvokerMap.put(key, invoker); } }else { newUrlInvokerMap.put(key, invoker); } } keys.clear(); return newUrlInvokerMap; }

在代码2处开始,如果url中包含key disabled,且key的值为true,则该提供者将不会转成调用者Invoker,消费者本地的提供者列表则不包含该提供者,那么消费者在调用提供者时,就不会再调用到该提供者。 处理完提供者列表后,接着将提供者列表转成方法名映射提供者关系,即消费者调用了某个方法,会根据方法映射到提供者,代码如下:

/** * 将invokers列表转成与方法的映射关系 * * @param invokersMap Invoker列表 * @return Invoker与方法的映射关系 */ private Map<String, List<Invoker<T>>> toMethodInvokers(Map<String, Invoker<T>> invokersMap) { Map<String, List<Invoker<T>>> newMethodInvokerMap = new HashMap<String, List<Invoker<T>>>(); // 按提供者URL所声明的methods分类,兼容注册中心执行路由过滤掉的methods List<Invoker<T>> invokersList = new ArrayList<Invoker<T>>(); if (invokersMap != null && invokersMap.size() > 0) { for (Invoker<T> invoker : invokersMap.values()) { String parameter = invoker.getUrl().getParameter(Constants.METHODS_KEY); if (parameter != null && parameter.length() > 0) { String[] methods = Constants.COMMA_SPLIT_PATTERN.split(parameter); if (methods != null && methods.length > 0) { for (String method : methods) { if (method != null && method.length() > 0 && ! Constants.ANY_VALUE.equals(method)) { List<Invoker<T>> methodInvokers = newMethodInvokerMap.get(method); if (methodInvokers == null) { methodInvokers = new ArrayList<Invoker<T>>(); newMethodInvokerMap.put(method, methodInvokers); } methodInvokers.add(invoker); } } } } invokersList.add(invoker); } } newMethodInvokerMap.put(Constants.ANY_VALUE, invokersList); if (serviceMethods != null && serviceMethods.length > 0) { for (String method : serviceMethods) { List<Invoker<T>> methodInvokers = newMethodInvokerMap.get(method); if (methodInvokers == null || methodInvokers.size() == 0) { methodInvokers = invokersList; } newMethodInvokerMap.put(method, route(methodInvokers, method)); //3处 } } // sort and unmodifiable for (String method : new HashSet<String>(newMethodInvokerMap.keySet())) { List<Invoker<T>> methodInvokers = newMethodInvokerMap.get(method); Collections.sort(methodInvokers, InvokerComparator.getComparator()); newMethodInvokerMap.put(method, Collections.unmodifiableList(methodInvokers)); } return Collections.unmodifiableMap(newMethodInvokerMap); }

在上面代码的3处,route方法实现了路由功能,路由功能在下章节讲到点击打开链接。

自己写了个RPC:

https://github.com/nytta

可以给个star,^0^.

转载请注明原文地址: https://www.6miu.com/read-59972.html

最新回复(0)