dubbo源码解析(8)dubbo服务引用

56 篇文章 2 订阅

入口找到ReferenceBean,关注到这个类继承了FactoryBean,熟悉spring的人知道继承了这个接口会通过

getObject()方法来获取bean,
public Object getObject() throws Exception {
    return get();
}

----->

public synchronized T get() {
    if (destroyed){
        throw new IllegalStateException("Already destroyed!");
    }
   if (ref == null) {
      init();
   }
   return ref;
}

init方法中核心方法是

ref = createProxy(map);这句话

map是服务引用的一些参数

 进入createProxy方法,关注

invoker = refprotocol.refer(interfaceClass, urls.get(0));

这里的refprotocol是一个Protocol$Apdative 这个是一个老朋友了,只是之前都是研究它的export方法,因为之前都是说服务暴露

在dubbo中Protocol接口有两个功能,一个是服务暴露,还有一个就是服务引用,这一篇我就研究refer方法

    public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws java.lang.Class {
        if (arg1 == null) throw new IllegalArgumentException("url == null");
        com.alibaba.dubbo.common.URL url = arg1;
        String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
        if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
        com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.refer(arg0, arg1);
    }
   

这里的extName =registry

根据之前服务暴露的源码分析,可以知道首先会进入ProtocolFilterWrapper#refer方法,

public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
    if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
        return protocol.refer(type, url);
    }
    return new ListenerInvokerWrapper<T>(protocol.refer(type, url), 
            Collections.unmodifiableList(
                    ExtensionLoader.getExtensionLoader(InvokerListener.class)
                    .getActivateExtension(url, Constants.INVOKER_LISTENER_KEY)));
}

这里会执行if分支,这里的protocol是ProtocolListenerWrapper

ProtocolListenerWrapper#refer

public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
    if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
        return protocol.refer(type, url);
    }
    return new ListenerInvokerWrapper<T>(protocol.refer(type, url), 
            Collections.unmodifiableList(
                    ExtensionLoader.getExtensionLoader(InvokerListener.class)
                    .getActivateExtension(url, Constants.INVOKER_LISTENER_KEY)));
}

protocol.refer(type, url)进入

Registry#refer

public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
       url = url.setProtocol(url.getParameter(Constants.REGISTRY_KEY, Constants.DEFAULT_REGISTRY)).removeParameter(Constants.REGISTRY_KEY);
       Registry registry = registryFactory.getRegistry(url);
       if (RegistryService.class.equals(type)) {
           return proxyFactory.getInvoker((T) registry, type, url);
       }

       // group="a,b" or group="*"
       Map<String, String> qs = StringUtils.parseQueryString(url.getParameterAndDecoded(Constants.REFER_KEY));
       String group = qs.get(Constants.GROUP_KEY);
       if (group != null && group.length() > 0 ) {
           if ( ( Constants.COMMA_SPLIT_PATTERN.split( group ) ).length > 1
                   || "*".equals( group ) ) {
               return doRefer( getMergeableCluster(), registry, type, url );
           }
       }
       return doRefer(cluster, registry, type, url);
   }

这里的Registry registry = registryFactory.getRegistry(url);和在上一篇说明的服务暴露一样,里面做了zookeeper的连接

关注最后一句话
return doRefer(cluster, registry, type, url);
private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
    RegistryDirectory<T> directory = new RegistryDirectory<T>(type, url);
    directory.setRegistry(registry);
    directory.setProtocol(protocol);
    URL subscribeUrl = new URL(Constants.CONSUMER_PROTOCOL, NetUtils.getLocalHost(), 0, type.getName(), directory.getUrl().getParameters());
    if (! Constants.ANY_VALUE.equals(url.getServiceInterface())
            && url.getParameter(Constants.REGISTER_KEY, true)) {
        registry.register(subscribeUrl.addParameters(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY,
                Constants.CHECK_KEY, String.valueOf(false)));
    }
    directory.subscribe(subscribeUrl.addParameter(Constants.CATEGORY_KEY, 
            Constants.PROVIDERS_CATEGORY 
            + "," + Constants.CONFIGURATORS_CATEGORY 
            + "," + Constants.ROUTERS_CATEGORY));
    return cluster.join(directory);
}
registry.register(subscribeUrl.addParameters(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY,
        Constants.CHECK_KEY, String.valueOf(false)));

这句话和我们之前服务暴露也一样,这里会在zookeeper创建consumer节点。

directory.subscribe(subscribeUrl.addParameter(Constants.CATEGORY_KEY, 
        Constants.PROVIDERS_CATEGORY 
        + "," + Constants.CONFIGURATORS_CATEGORY 
        + "," + Constants.ROUTERS_CATEGORY));

这里也和之前服务暴露一样,是订阅监听zk

zookeeperRegistry#doSubscribe

for (String path : toCategoriesPath(url)) {
    ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url);
    if (listeners == null) {
        zkListeners.putIfAbsent(url, new ConcurrentHashMap<NotifyListener, ChildListener>());
        listeners = zkListeners.get(url);
    }
    ChildListener zkListener = listeners.get(listener);
    if (zkListener == null) {
        listeners.putIfAbsent(listener, new ChildListener() {
            public void childChanged(String parentPath, List<String> currentChilds) {
               ZookeeperRegistry.this.notify(url, listener, toUrlsWithEmpty(url, parentPath, currentChilds));
            }
        });
        zkListener = listeners.get(listener);
    }
    zkClient.create(path, false);
    List<String> children = zkClient.addChildListener(path, zkListener);
    if (children != null) {
       urls.addAll(toUrlsWithEmpty(url, path, children));
    }
}

这里会for循环toCategoriesPath(url)

 可以知道消费者是订阅提供者,配置以及路由三个节点

这部分代码基本都一样,只看这句话

listener.notify(categoryList);

因为这里的listener=RegistryDirectory

进入RegistryDirectory#notify

refreshInvoker(invokerUrls);

这里面的逻辑用注释来说明

根据invokerURL列表转换为invoker列表。转换规则如下:
* 1.如果url已经被转换为invoker,则不在重新引用,直接从缓存中获取,注意如果url中任何一个参数变更也会重新引用
* 2.如果传入的invoker列表不为空,则表示最新的invoker列表
* 3.如果传入的invokerUrl列表是空,则表示只是下发的override规则或route规则,需要重新交叉对比,决定是否需要重新引用。

回到RegistryProtocol#doRefer方法

 cluster.join(directory);

这里的cluster是Cluster$Adaptive

public com.alibaba.dubbo.rpc.Invoker join(com.alibaba.dubbo.rpc.cluster.Directory arg0)
    throws com.alibaba.dubbo.rpc.cluster.Directory {
    if (arg0 == null) {
        throw new IllegalArgumentException("com.alibaba.dubbo.rpc.cluster.Directory argument == null");
    }
    if (arg0.getUrl() == null) {
        throw new IllegalArgumentException("com.alibaba.dubbo.rpc.cluster.Directory argument getUrl() == null");
    }
    com.alibaba.dubbo.common.URL url = arg0.getUrl();
    String extName = url.getParameter("cluster", "failover");
    if (extName == null) {
        throw new IllegalStateException(
            "Fail to get extension(com.alibaba.dubbo.rpc.cluster.Cluster) name from url(" + url.toString()
                + ") use keys([cluster])");
    }
    com.alibaba.dubbo.rpc.cluster.Cluster extension = (com.alibaba.dubbo.rpc.cluster.Cluster)ExtensionLoader
        .getExtensionLoader(com.alibaba.dubbo.rpc.cluster.Cluster.class).getExtension(extName);
    return extension.join(arg0);
}

extName=failover,

得到的extension=MockClusterWrapper

public class MockClusterWrapper implements Cluster {

   private Cluster cluster;

   public MockClusterWrapper(Cluster cluster) {
      this.cluster = cluster;
   }

   public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
      return new MockClusterInvoker<T>(directory,
            this.cluster.join(directory));
   }

}

join方法中会创建一个MockClusterInvoker,其中的参数是directory以及FailoverCluster#join方法返回的invoker

 

所以回到ReferenceConfig#createproxy

invoker = refprotocol.refer(interfaceClass, urls.get(0));

invoker=MockClustgerinvoker

看到

return (T) proxyFactory.getProxy(invoker);

proxyFactory=proxyFactory$Adaptive

extName=javassist

extension=StubProxyFactoryWrapper

进入StubProxyFactoryWrapper#getProxy

T proxy = proxyFactory.getProxy(invoker);

javassistProxyFacotry的getPorxy一个参数的方法在AbstaractProxyFacotry中

直接找到最后一句话

return getProxy(invoker, interfaces);
@SuppressWarnings("unchecked")
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
    return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}

这里和jdk的动态代理非常像

这里就是返回一个interfaces的代理对象,interface=

 

返回

StubProxyFactoryWrapper#getProxy

proxy为

 

 所以实际上我们在consumer,自动注入的接口就是一个代理类

---------------------------------------------

说了这么多,总结下服务引用的结构图,用下面一张图来描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值