赞
踩
根据方法的层级,整理的方法调用步骤层级.
- 1、2、3、4在一条调用链上
- 第5里面会调用第6步
- 5、7、8在同一个方法的同一级
在通过Spring对含有@Reference注解的属性进行属性填充,会调用到get方法
get方法位于ReferenceBean的父类ReferenceConfig中。
在该方法中主要进行参数检查,然后掉哦那个init方法
在Dubbo服务导出阶段也含有类似checkAndUpdateSubConfigs这个步骤。调用checkAndUpdateSubConfigs()方法,检查和更新参数,和服务提供者类似,把ReferenceBean里的属性的值更新为优先级最高的参数值
该方法同样类似Dubbo服务导出阶段逻辑,把消费者所引入服务设置的参数添加到一个map中,等会根据这个map中的参数去从注册中心查找服务,然后对查找到的服务生成一个代理对象,设置到ref参数上。
前面第2步说到的调用get方法,最终返回的也就是这个ref参数所代表的服务代理对象
下面提到的5、6、7、8几点,都是在该方法中完成的
这里主要的逻辑为调用到RegistryProtocol类的refer方法,但是在调到对应的refer方法之前,会先经过相关的包装类ProtocolListenerWrapper和ProtocolFilterWrapper的refer方法。
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException { // 从registry://的url中获取对应的注册中心,比如zookeeper, 默认为dubbo,dubbo提供了自带的注册中心实现 // url由 registry:// 改变为---> zookeeper:// url = URLBuilder.from(url) .setProtocol(url.getParameter(REGISTRY_KEY, DEFAULT_REGISTRY)) .removeParameter(REGISTRY_KEY) .build(); // 拿到注册中心实现,ZookeeperRegistry Registry registry = registryFactory.getRegistry(url); // 下面这个代码,通过过git历史提交记录是用来解决SimpleRegistry不可用的问题 if (RegistryService.class.equals(type)) { return proxyFactory.getInvoker((T) registry, type, url); } // qs表示 queryString, 表示url中的参数,表示消费者引入服务时所配置的参数 Map<String, String> qs = StringUtils.parseQueryString(url.getParameterAndDecoded(REFER_KEY)); // group="a,b" or group="*" // https://dubbo.apache.org/zh/docs/v2.7/user/examples/group-merger/ String group = qs.get(GROUP_KEY); if (group != null && group.length() > 0) { if ((COMMA_SPLIT_PATTERN.split(group)).length > 1 || "*".equals(group)) { // group有多个值,这里的cluster为MergeableCluster return doRefer(getMergeableCluster(), registry, type, url); } } // 这里的cluster是cluster的Adaptive对象,扩展点 return doRefer(cluster, registry, type, url); }
在该方法中会有一个服务目录的概念,即RegistryDirectory类。
该方法的主题逻辑为:
- 根据传入的消费者类型和注册中心url,初始化一个服务目录RegistryDirectory对象
- 构建对应的路由器链(可在引入服务时按路由条件进行过滤),并添加到RegistryDirectory中去
- 监听Dubobo-admin客户端相关的目录,可用来动态修改服务目录对象的值
- 初始化相关的ClusterInvoker对象
private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) { // RegistryDirectory表示动态服务目录,会和注册中心的数据保持同步 // type表示一个服务对应一个RegistryDirectory,url表示注册中心地址 // 在消费端,最核心的就是RegistryDirectory RegistryDirectory<T> directory = new RegistryDirectory<T>(type, url); directory.setRegistry(registry); directory.setProtocol(protocol); // all attributes of REFER_KEY // 引入服务所配置的参数 Map<String, String> parameters = new HashMap<String, String>(directory.getUrl().getParameters()); // 消费者url URL subscribeUrl = new URL(CONSUMER_PROTOCOL, parameters.remove(REGISTER_IP_KEY), 0, type.getName(), parameters); if (!ANY_VALUE.equals(url.getServiceInterface()) && url.getParameter(REGISTER_KEY, true)) { directory.setRegisteredConsumerUrl(getRegisteredConsumerUrl(subscribeUrl, url)); // 注册简化后的消费url registry.register(directory.getRegisteredConsumerUrl()); } // 构造路由链,路由链会在引入服务时按路由条件进行过滤 // 路由链是动态服务目录中的一个属性,通过路由链可以过滤某些服务提供者 directory.buildRouterChain(subscribeUrl); // 服务目录需要订阅的几个路径 // 当前应用所对应的动态配置目录:/dubbo/config/dubbo/dubbo-demo-consumer-application.configurators // 当前所引入的服务的动态配置目录:/dubbo/config/dubbo/org.apache.dubbo.demo.DemoService:1.1.1:g1.configurators // 当前所引入的服务的提供者目录:/dubbo/org.apache.dubbo.demo.DemoService/providers // 当前所引入的服务的老版本动态配置目录:/dubbo/org.apache.dubbo.demo.DemoService/configurators // 当前所引入的服务的老版本路由器目录:/dubbo/org.apache.dubbo.demo.DemoService/routers directory.subscribe(subscribeUrl.addParameter(CATEGORY_KEY, PROVIDERS_CATEGORY + "," + CONFIGURATORS_CATEGORY + "," + ROUTERS_CATEGORY)); // 利用传进来的cluster,join得到invoker, MockClusterWrapper Invoker invoker = cluster.join(directory); ProviderConsumerRegTable.registerConsumer(invoker, url, subscribeUrl, directory); return invoker; }
1)构建路由链
2)监听对应目录
RegistryDirectory.subscribe --> FailbackRegistry.subscribe --> FailbackRegistry.subscribe --> ZookeeperRegistry.doSubscribe
在该方法中,会创建对应的注册中心连接,然后绑定对应的需要监听的路径path。这个path对应的路径就是第一步传进来的url,即包含目录为:
subscribeUrl.addParameter(CATEGORY_KEY, PROVIDERS_CATEGORY + "," + CONFIGURATORS_CATEGORY + "," + ROUTERS_CATEGORY)
- 1
- 2
- CATEGORY_KEY:服务基础路径/category(老版本目录)
- PROVIDERS_CATEGORY:服务基础路径/providers(老版本目录)
- CONFIGURATORS_CATEGORY:服务基础路径/configurators(新版本目录)
- ROUTERS_CATEGORY:服务基础路径/routers(老版本目录)
3)调用join方法完成对象初始化
添加相关Invoker方法作用:
将多个或一个invokers根据相关的规则处理得到唯一的一个invoker对象,用于下一步生成对应的代理对象。
这里分为两种情况:
1、这里只对第一种情况进行说明第一种情况
这里调用的是RegistryAwareCluster类的join方法,join方法会实例化出一个Invoker,最终会调用到每个Invoker的invoke方法。
在wrapper包装Invoker类中,会先进行mock判断,是否需要进行mock处理
这里使用了模板方法模式,在调用类的invoke方法时,会直接调用到其父类AbstractClusterInvoker的invoke方法,然后再执行具体子类的doInvoke方法
在父类就能够完成多个invoker的负载均衡处理
这里默认使用Javassist代理方式
传入前面过滤后剩下的一个Invoke,为其生成一个代理对象,返回给调用处
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。