dubbo源码解析——Directory
首先来看一下directory接口的实现类,他主要有两个实现类,一个是StaticDirectory,一个是RegistryDirectory,本文主要解析RegistryDirectory。
StaticDirectory
StaticDirectory中的Static关键词来看,就知道,这个其实是不会动态变化的,从下图知道,他的Invoker是通过构造函数传入,StaticDirectory用得比较少,主要用在服务对多注册中心的引用
RegistryDirectory
首先看下它的结构:
这个NotifyListener中的notify方法就是注册中心的回调,也就是它之所以能根据注册中心动态变化的根源所在.
上文中,Directory的doList方法,这是一个抽象方法,通过调用子类RegistryDirectory的doList方法,从Directory中选择出invoker列表。
@Override public List<Invoker<T>> doList(Invocation invocation) { if (forbidden) { // 如果forbidden为true,则没有服务提供者 或者 服务提供者不可用 throw new RpcException(RpcException.FORBIDDEN_EXCEPTION, "No provider available from registry " + getUrl().getAddress() + " for service " + getConsumerUrl().getServiceKey() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", please check status of providers(disabled, not registered or in blacklist)."); } List<Invoker<T>> invokers = null; Map<String, List<Invoker<T>>> localMethodInvokerMap = this.methodInvokerMap; if (localMethodInvokerMap != null && localMethodInvokerMap.size() > 0) { // 获取方法名称 String methodName = RpcUtils.getMethodName(invocation); // 获取方法参数 Object[] args = RpcUtils.getArguments(invocation); if (args != null && args.length > 0 && args[0] != null && (args[0] instanceof String || args[0].getClass().isEnum())) { // 如果第一个参数是字符串类型 或者 枚举类型 // 可以根据第一个参数枚举路由 invokers = localMethodInvokerMap.get(methodName + "." + args[0]); } if (invokers == null) { // 仍然为null,使用方法名称获取 invokers = localMethodInvokerMap.get(methodName); } if (invokers == null) { // 仍让为null,使用 * 随机取一个invoker来实现调用 invokers = localMethodInvokerMap.get(Constants.ANY_VALUE); } if (invokers == null) { // 仍然为null,使用迭代器获取一个invoker Iterator<List<Invoker<T>>> iterator = localMethodInvokerMap.values().iterator(); if (iterator.hasNext()) { invokers = iterator.next(); } } } return invokers == null ? new ArrayList<Invoker<T>>(0) : invokers; }
从中可以看出,Directory获取invoker是从methodInvokerMap中获取的。invoker什么时候写入到Directory的methodInvokerMap里面呢?就是在回调方法notify的时候操作的。
@Override public synchronized void notify(List<URL> urls) { // 声明invoker的URL引用数组 List<URL> invokerUrls = new ArrayList<URL>(); // 声明router的URL引用数组 List<URL> routerUrls = new ArrayList<URL>(); // 声明configurator(配置器)的URL引用数组 List<URL> configuratorUrls = new ArrayList<URL>(); for (URL url : urls) { // 获取协议名称 String protocol = url.getProtocol(); // 获取分类 String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY); if (Constants.ROUTERS_CATEGORY.equals(category) || Constants.ROUTE_PROTOCOL.equals(protocol)) { // 如果是路由分类 或者 路由协议 routerUrls.add(url); } else if (Constants.CONFIGURATORS_CATEGORY.equals(category) || Constants.OVERRIDE_PROTOCOL.equals(protocol)) { // 如果是配置器分类 或者 重写协议 configuratorUrls.add(url); } else if (Constants.PROVIDERS_CATEGORY.equals(category)) { // 如果是提供方分类 invokerUrls.add(url); } else { logger.warn("Unsupported category " + category + " in notified url: " + url + " from registry " + getUrl().getAddress() + " to consumer " + NetUtils.getLocalHost()); } } // 通过url获取configurators if (configuratorUrls != null && !configuratorUrls.isEmpty()) { this.configurators = toConfigurators(configuratorUrls); } // 通过url获取routers if (routerUrls != null && !routerUrls.isEmpty()) { List<Router> routers = toRouters(routerUrls); if (routers != null) { // null - do nothing setRouters(routers); } } List<Configurator> localConfigurators = this.configurators; // 合并override参数 this.overrideDirectoryUrl = directoryUrl; if (localConfigurators != null && !localConfigurators.isEmpty()) { for (Configurator configurator : localConfigurators) { this.overrideDirectoryUrl = configurator.configure(overrideDirectoryUrl); } } // 刷新providers refreshInvoker(invokerUrls); } /** * 把invokerUrl列表 转化成 invoker Map。转换规则如下 * 1.如果URL已经转换为invoker,则不再重新引用它,并且直接从缓存中获得它,并且注意URL中的任何参数更改都将被重新引用。 * 2.如果传入的invoker列表不是空的,则意味着它是最新的调用列表。 * 3.如果传入的invokerUrl列表为空,则意味着该规则仅是重写规则或路由规则,需要对其进行重新对比以决定是否重新引用。 * @param invokerUrls this parameter can't be null */ private void refreshInvoker(List<URL> invokerUrls) { if (invokerUrls != null && invokerUrls.size() == 1 && invokerUrls.get(0) != null && Constants.EMPTY_PROTOCOL.equals(invokerUrls.get(0).getProtocol())) { // 只有一个invoker url,并且协议是空协议 // 设置禁止访问 this.forbidden = true; // 设置methodInvokerMap为null this.methodInvokerMap = null; // 关闭所有invoker destroyAllInvokers(); } else { // 设置允许访问 this.forbidden = false; Map<String, Invoker<T>> oldUrlInvokerMap = this.urlInvokerMap; if (invokerUrls.isEmpty() && this.cachedInvokerUrls != null) { // 如果传入的invoker url是空的,从缓存中添加 invokerUrls.addAll(this.cachedInvokerUrls); } else { // 缓存invoker url,便于比较 this.cachedInvokerUrls = new HashSet<URL>(); this.cachedInvokerUrls.addAll(invokerUrls); } if (invokerUrls.isEmpty()) { return; } // 把invoker url列表 转换成 key为url,value为invoker的Map Map<String, Invoker<T>> newUrlInvokerMap = toInvokers(invokerUrls); // 把invoker url列表 转换成 key为method,value为invoker的Map Map<String, List<Invoker<T>>> newMethodInvokerMap = toMethodInvokers(newUrlInvokerMap); 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; } // 如果有多个分组,就合并methodInvokerMap this.methodInvokerMap = multiGroup ? toMergeMethodInvokerMap(newMethodInvokerMap) : newMethodInvokerMap; this.urlInvokerMap = newUrlInvokerMap; try { // 关闭没有使用invoker destroyUnusedInvokers(oldUrlInvokerMap, newUrlInvokerMap); } catch (Exception e) { logger.warn("destroyUnusedInvokers error. ", e); } } }
也就是注册中心有变化,则更新methodInvokerMap和urlInvokerMap的值(这个后面讲服务引用原理的时候会再提一下),这就是官网提到的它的值可能是动态变化的,比如注册中心推送变更的原因所在
相关推荐
waiwaiLILI 2020-11-03
bxqybxqy 2020-09-30
microsoft00 2020-09-11
strburnchang 2020-07-04
wenjieyatou 2020-06-12
zyjj 2020-06-08
wmliang00 2020-05-30
赵家小少爷 2020-05-16
小惠 2020-05-12
csdmeb 2020-05-01
咏月东南 2020-04-20
csdnyasin 2020-04-11
简单的快乐 2020-04-09
王志龙 2020-03-07
adc00 2020-02-16
TyCoding 2020-02-01
hickwu 2020-01-31