Dubbo消费者启动过程 笔记

dubbo源码需要先了解dubbo的SPI机制,官网说明如下

http://dubbo.apache.org/zh-cn/docs/source_code_guide/dubbo-spi.html

入口 org.apache.dubbo.config.spring.ReferenceBean 的 afterPropertiesSet(),跳过前面一些配置检查直接看 getObject()

进入getObject()

 接着进入就到了 ReferenceConfig 中

进入init() 直接看 ref =  createProxy(map);

 看到 invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0)); 因为只配置了一个注册中心,所以走 if 逻辑 

REF_PROTOCOL 是一个扩展点,注释也写的很清楚,此时的 url 如下

registry://192.168.50.135:2181/org.apache.dubbo.registry.RegistryService?application=springboot-dubbo-client&dubbo=2.0.2&pid=2468&qos.enable=false&refer=application%3Dspringboot-dubbo-client%26dubbo%3D2.0.2%26interface%3Dcom.david.dubbo.SayHelloService%26lazy%3Dfalse%26methods%3DsayHello%2CsayHi%2CsayBye%26pid%3D2468%26qos.enable%3Dfalse%26register.ip%3D192.168.50.1%26release%3D2.7.3%26revision%3D1.0-SNAPSHOT%26side%3Dconsumer%26sticky%3Dfalse%26timestamp%3D1588126009153&registry=zookeeper&release=2.7.3&timestamp=1588126009283

根据协议生成的是 RegistryProtocol

REF_PROTOCOL是一个自适应扩展点,根据之前的经验会获得一个RegisterProtocol,查看生成类

public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {
    public void destroy() {
        throw new UnsupportedOperationException("The method public abstract void org.apache.dubbo.rpc.Protocol.destroy() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }

    public int getDefaultPort() {
        throw new UnsupportedOperationException("The method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }

    public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
        if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
        if (arg0.getUrl() == null)
            throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
        org.apache.dubbo.common.URL url = arg0.getUrl();
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
        org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.export(arg0);
    }

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

进入 RegisterProtocol 的 refer

这里下面这段代码把url中的协议替换成了zookeeper

url = URLBuilder.from(url).setProtocol(url.getParameter("registry", "dubbo")).removeParameter("registry").build();

此时 registryFactory 是一个injection注入类

debug查看生成代码 

public class RegistryFactory$Adaptive implements org.apache.dubbo.registry.RegistryFactory {
    public org.apache.dubbo.registry.Registry getRegistry(org.apache.dubbo.common.URL arg0) {
        if (arg0 == null) throw new IllegalArgumentException("url == null");
        org.apache.dubbo.common.URL url = arg0;
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException("Failed to get extension (org.apache.dubbo.registry.RegistryFactory) name from url (" + url.toString() + ") use keys([protocol])");
        org.apache.dubbo.registry.RegistryFactory extension = (org.apache.dubbo.registry.RegistryFactory) ExtensionLoader.getExtensionLoader(org.apache.dubbo.registry.RegistryFactory.class).getExtension(extName);
        return extension.getRegistry(arg0);
    }
}

因为 protocol 是 zookeeper 所以会调用 ZookeeperRegistryFactory 的 getRegister()

ZookeeperRegistryFactory 中没有 getRegister 方法,进入父类 AbstractRegistryFactory 中找到 getRegister

 registry = createRegistry(url); 跳转回 ZookeeperRegistryFactory  返回一个 ZookeeperRegistry,这里传入了一个zookeeperTransporter,是 injectExtension 注入

 重新debug看看生成的类如下

public class ZookeeperTransporter$Adaptive implements org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter {
    public org.apache.dubbo.remoting.zookeeper.ZookeeperClient connect(org.apache.dubbo.common.URL arg0) {
        if (arg0 == null) throw new IllegalArgumentException("url == null");
        org.apache.dubbo.common.URL url = arg0;
        String extName = url.getParameter("client", url.getParameter("transporter", "curator"));
        if (extName == null)
            throw new IllegalStateException("Failed to get extension (org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter) name from url (" + url.toString() + ") use keys([client, transporter])");
        org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter extension = (org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter) ExtensionLoader.getExtensionLoader(org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter.class).getExtension(extName);
        return extension.connect(arg0);
    }
}

 进入zookeeperRegistry,此时的url

zookeeper://192.168.50.135:2181/org.apache.dubbo.registry.RegistryService?application=springboot-dubbo-client&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=10016&qos.enable=false&release=2.7.3&timestamp=1588131010498

根据url和上面商城的代码调用的是 curator 

 进入 CuratorZookeeperTransporter ,发现没有 connect() 方法,进入父类中找

 AbstractZookeeperTransporter.connect()

 new CuratorZookeeperClient(url)

key = zookeeper://192.168.50.135:2181/org.apache.dubbo.registry.RegistryService

 进入CuratorZookeeperClient

client = builder.build();

这里已经进入了 curator 的 api 当中了

 

接着返回 RegistryProtocol 中,应为当前 protocol 已经是 zookeeper,所以会走else

进入doRefer方法

重点是 directory.subscribe 订阅监听

进入 RegistryDirectory 的subscribe

这里把 this 也就是 RegistryDirectory  传递了进去

这里的 registry 是 之前创建好的 ZookeeperRegistry 但是却没有该方法,找到其父类中该方法。

进入FailbackRegistry 的 subscribe方法

 在FailbackRegistry 又调用子类

回到 ZookeeperRegistry ,if 条件不满足走else

 toCategoriesPath(url) 是zk服务接口下面的三个地址,会分别做监听

然后在对子节点做监听 List<String> children = zkClient.addChildListener(path, zkListener);

重点关注  notify(url, listener, urls);,这里会对节点上的服务做感知

 进入notify

  进入父类 AbstractRegistry.notify

 saveProperties(url); 会对服务地址做一个缓存,当zk挂了可以继续使用本地缓存

listener.notify(categoryList); 会拿到服务站的url地址做一个通知 , 也就是 RegistryDirectory的notify,这里会循环三次,只看service的url

overrideDirectoryUrl(); // 覆盖
refreshInvoker(urls);  // 刷新Invoker,构建代理对象

注释也写得很清楚,将 url 转换为 invoker,重点在 toInvikers


urlInvokerMap = newUrlInvokerMap;  urlInvokerMap是存放了所有服务地址的集合.

进入 toInvikers

重点在这句代码 invoker = new InvokerDelegate<>(protocol.refer(serviceType, url), url, providerUrl);
这里的 protocol 是一个自适应扩展点,根据当前的 url 协议是dubbo,最后会进入dubboProtocol,但是这不是一个单存的dubboProtocol,这个dubbo根据扩展点又被Wrapper所包装,

所以现在是InvokerDelegate(ProtocolFilterWrapper(ListenerInvokerWrapper(DubboInvoker)))

ProtocolFilterWrapper、ListenerInvokerWrapper 这两个类会构建一条调用链。

所以现在进入 DubboProtocol 中 ,进去后发现没有这个方法,按规矩找父类  AbstractProtocol

在接着进入DubboProtocol.protocolBindingRefer 

InvokerDelegate(DubboInvoker)

进入  getClients(url)

进入 getSharedClient()

 然后进入this.buildReferenceCountExchangeClientList

继续 clients.add(this.buildReferenceCountExchangeClient(url));
 ExchangeClient exchangeClient = initClient(url);

进入client = Exchangers.connect(url, this.requestHandler);

 private ExchangeClient initClient(URL url) {
        String str = url.getParameter("client", url.getParameter("server", "netty"));
        url = url.addParameter("codec", "dubbo");
        url = url.addParameterIfAbsent("heartbeat", String.valueOf(60000));
        if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) {
            throw new RpcException("Unsupported client type: " + str + ", supported client type is " + StringUtils.join(ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions(), " "));
        } else {
            try {
                Object client;
                if (url.getParameter("lazy", false)) {
                    client = new LazyConnectExchangeClient(url, this.requestHandler);
                } else {
                    client = Exchangers.connect(url, this.requestHandler);
                }

                return (ExchangeClient)client;
            } catch (RemotingException var5) {
                throw new RpcException("Fail to create remoting client for service(" + url + "): " + var5.getMessage(), var5);
            }
        }
    }

这里个服务端注册一样,根据url拿到一个netty服务,把当前根据url构建好的服务封装到 ReferenceCountExchangeClient中返回。

这里到了 Exchangers  后面又是一个扩展点 ,跟服务发布的过程一样了,也是构建个netty服务

public static ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
        if (url == null) {
            throw new IllegalArgumentException("url == null");
        } else if (handler == null) {
            throw new IllegalArgumentException("handler == null");
        } else {
            url = url.addParameterIfAbsent("codec", "exchange");
            return getExchanger(url).connect(url, handler);
        }
    }

    public static Exchanger getExchanger(URL url) {
        String type = url.getParameter("exchanger", "header");
        return getExchanger(type);
    }

    public static Exchanger getExchanger(String type) {
        return (Exchanger)ExtensionLoader.getExtensionLoader(Exchanger.class).getExtension(type);
    }

HeaderExchanger 

public class HeaderExchanger implements Exchanger {
    public static final String NAME = "header";

    public HeaderExchanger() {
    }

    public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
        return new HeaderExchangeClient(Transporters.connect(url, new ChannelHandler[]{new DecodeHandler(new HeaderExchangeHandler(handler))}), true);
    }

    public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
        return new HeaderExchangeServer(Transporters.bind(url, new ChannelHandler[]{new DecodeHandler(new HeaderExchangeHandler(handler))}));
    }
}

Transporter

public static Client connect(URL url, ChannelHandler... handlers) throws RemotingException {
        if (url == null) {
            throw new IllegalArgumentException("url == null");
        } else {
            Object handler;
            if (handlers != null && handlers.length != 0) {
                if (handlers.length == 1) {
                    handler = handlers[0];
                } else {
                    handler = new ChannelHandlerDispatcher(handlers);
                }
            } else {
                handler = new ChannelHandlerAdapter();
            }

            return getTransporter().connect(url, (ChannelHandler)handler);
        }
    }

    public static Transporter getTransporter() {
        return (Transporter)ExtensionLoader.getExtensionLoader(Transporter.class).getAdaptiveExtension();
    }

进入到netty了

public class NettyTransporter implements Transporter {
    public static final String NAME = "netty";

    public NettyTransporter() {
    }

    public Server bind(URL url, ChannelHandler listener) throws RemotingException {
        return new NettyServer(url, listener);
    }

    public Client connect(URL url, ChannelHandler listener) throws RemotingException {
        return new NettyClient(url, listener);
    }
}

往前返回就会把一个带有netty服务的代理对象赋值给我们的接口类,当接口发起调用就会调用代理对象中的方法获得到方法名、参数值传递下去发起远程调用。

订阅完成之后会返回到 RegistryProtocol,后面会把这个包装过的directory返回给代理对象注入到我们引用的接口类中。

cluster = MockClusterInvoker(FailoverClusterInvoker(directory))

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值