五Dubbo服务引用源码分析--2创建远程调用的代理-2.4DubboProtocol.refer

五Dubbo服务引用源码分析--2创建远程调用的代理-2.4DubboProtocol.refer

继续上篇文章内容,向下分析DubboProtocol.refer的源码:

/**…………DubboProtocol.refer………………*/
INV InvokerDelegate(protocol.refer(serviceType, url), url, providerUrl)
public class Protocol$Adaptive implements com.alibaba.dubbo.rpc.Protocol {

   public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException {
        if (arg1 == null) throw new IllegalArgumentException("url == null");
        com.alibaba.dubbo.common.URL url = arg1;
        String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() ); //dubbo
        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);
//INV1 Qos/Filter/Listener/Dubbo.refer
        return extension.refer(arg0, arg1);
    }

这里extension为包裹过的protocol

image-20221230180021418

url参数=dubbo://192.168.0.100:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demotest-consumer&bean.name=com.alibaba.dubbo.demo.DemoService&check=false&dubbo=2.0.2&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=getPermissions&organization=dubbox&owner=programmer&pid=75508&qos.enable=false&register.ip=192.168.0.100&remote.timestamp=1672381137107&side=consumer&timestamp=1672387055607
INV1 Qos/Filter/Listener/Dubbo.refer
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
    if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
        startQosServer(url);
        return protocol.refer(type, url);
    }
  //对于dubbo://协议处理(传递到内层wrapper上)
    return protocol.refer(type, url);
}
ProtocolFilterWrapper
   public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
        if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
            return protocol.refer(type, url);
        }
//INV1.1 buildInvokerChain
  //这里,首先进行protocol.refer,然后,根据返回的invoker构造拦截器链
        return buildInvokerChain(protocol.refer(type, url), Constants.REFERENCE_FILTER_KEY, Constants.CONSUMER);
    }
ProtocolListenerWrapper
   public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
        if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
            return protocol.refer(type, url);
        }
  		//首先执行protocol.refer,然后,创建ListenerInvokerWrapper,其会在服务引用时,执行listener.referred的监听操作
        return new ListenerInvokerWrapper<T>(protocol.refer(type, url),
                Collections.unmodifiableList(
                        ExtensionLoader.getExtensionLoader(InvokerListener.class)
                                .getActivateExtension(url, Constants.INVOKER_LISTENER_KEY)));
    }
INV2 DubboProtocol.refer--创建RPC功能invoker

serviceType为调用服务的接口,URL以dubbo开头,后续跟了dubbo服务地址,以及服务名称DemoService,该url描述了一个dubbo协议的服务。因此,refer此处逻辑,是调用远程host处dubbo协议的demoService的服务。

DubboProtocol.refer
    public <T> Invoker<T> refer(Class<T> serviceType, URL url) throws RpcException {
        optimizeSerialization(url);
        // 创建RPC功能的invoker
//INV2.1 getClients(url)
//INV2.2 DubboInvoker
        DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url), invokers);
      		//将创建好的invoker加入集合
        invokers.add(invoker);
        return invoker;
    }

上述创建RPC功能的invoker。参数中,getClients(url)获取客户端实例,为ExchangeClient。

//INV2.1 getClients(url)--创建client客户端

getClients(URL)方法,根据url中参数,判定是否需要共享连接,获取客户端。

DubboProtocol
    private ExchangeClient[] getClients(URL url) {
        // 是否共享连接connection
        boolean service_share_connect = false;
        int connections = url.getParameter(Constants.CONNECTIONS_KEY, 0);
        // if not configured, connection is shared, otherwise, one connection for one service
  			//如果url中没有配置connection连接的数量,表示共享;否则,一个连接对应一个service服务
        if (connections == 0) {
            service_share_connect = true;
            connections = 1;
        }

        ExchangeClient[] clients = new ExchangeClient[connections];
        for (int i = 0; i < clients.length; i++) {
            if (service_share_connect) {
//INV2.1.1 getSharedClient(url)获取共享连接connection
                clients[i] = getSharedClient(url);
            } else {
                clients[i] = initClient(url);
            }
        }
        return clients;
    }
//INV2.1.1 getSharedClient(url)获取共享连接connection

此处,跟入getSharedClient获取共享客户端方法

dubbo://192.168.0.100:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demotest-consumer&bean.name=com.alibaba.dubbo.demo.DemoService&check=false&dubbo=2.0.2&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=getPermissions&organization=dubbox&owner=programmer&pid=75508&qos.enable=false&register.ip=192.168.0.100&remote.timestamp=1672381137107&side=consumer&timestamp=1672387055607

url参数:

//DubboProtocol
private ExchangeClient getSharedClient(URL url) {
    String key = url.getAddress(); //192.168.0.100:20880
    //检查缓存
    ReferenceCountExchangeClient client = referenceClientMap.get(key);
  //1 当本地缓存中有客户端,返回
    if (client != null) {
        if (!client.isClosed()) {
          	//如果dubboProtocol的exchangeClient缓存中有address对应的客户端,则返回客户端共享,并增加引用计数(“引用计数”功能的 ExchangeClient)
            client.incrementAndGetCount();
            return client;
        } else {
          //当client关闭,从缓存移除
            referenceClientMap.remove(key);
        }
    }
		
//2 当缓存没有client,新建
    locks.putIfAbsent(key, new Object());
  //对当前address加锁,
    synchronized (locks.get(key)) {
        if (referenceClientMap.containsKey(key)) {
            return referenceClientMap.get(key);
        }

/**……………………………………………………………………………………………………创建客户端…………………………………………………………………………………………………… */
//INV2.1.2 initClient(url) 创建exchangeClient
        // 创建 ExchangeClient 客户端
        ExchangeClient exchangeClient = initClient(url);
        // 将 ExchangeClient 实例传给 ReferenceCountExchangeClient,这里使用了装饰模式
        client = new ReferenceCountExchangeClient(exchangeClient, ghostClientMap);
    //加锁,将key-client入缓存
        referenceClientMap.put(key, client);
        ghostClientMap.remove(key);
        locks.remove(key);
        return client;
    }
}

getSharedClient(URL url)方法获取共享客户端,首先会先从DubboProtocol本地缓存获取;如果没有,加锁创建新客户端initClient,并存入缓存。继续跟入创建新客户端代码:

//INV2.1.2 initClient(url) 创建exchangeClient
   private ExchangeClient initClient(URL url) {

    // 获取客户端client类型,默认为 netty
    String str = url.getParameter(Constants.CLIENT_KEY, url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_CLIENT));

    // 添加编解码和心跳包参数到 url 中
    url = url.addParameter(Constants.CODEC_KEY, DubboCodec.NAME);
    url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT));

    // 检测客户端类型,是否是Dubbo所支持的(transport为底层通信,目前支持Mina、Netty、Grizzly)
    if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) {
        throw new RpcException("Unsupported client type: ...");
    }

    ExchangeClient client;
    try {
        // 获取 lazy 配置
        if (url.getParameter(Constants.LAZY_CONNECT_KEY, false)) {
            // 创建懒加载 ExchangeClient 实例
            client = new LazyConnectExchangeClient(url, requestHandler);
        } else {
//INV2.1.3 Exchangers.connect(url, requestHandler)--CONN
            // 创建普通 ExchangeClient 实例
            client = Exchangers.connect(url, requestHandler);
        }
    } catch (RemotingException e) {
        throw new RpcException("Fail to create remoting client for service...");
    }
    return client;
   }

initClient(URL)中,通过向url中添加parm参数,添加心跳、编解码等处理器。然后通过Exchangers.connect(url, requestHandler)创建ExchangeClient。

//INV2.1.3 Exchangers.connect(url, requestHandler)--CONN
//INV2.1.3 Exchangers.connect(url, requestHandler)--CONN
            // 创建普通 ExchangeClient 实例
            client = Exchangers.connect(url, requestHandler);
        }
CONN1 ExchangeHandlerAdapter--处理providers请求

image-20221231155131798

image-20221231155331970

处理器为DubboProtocol内创建的属性。看出,该handler是Netty框架内存放在pipeline上的channelHandler,用于在消息传递中进行拦截、处理的类。

DubboProtocol
//provider端用于处理request的处理器
 private ExchangeHandler requestHandler = new ExchangeHandlerAdapter() {

  			//处理调用请求
        public Object reply(ExchangeChannel channel, Object message) throws RemotingException {
          //handler只处理Invocation的信息
            if (message instanceof Invocation) { //1 
                Invocation inv = (Invocation) message;
/**…………………………………………………………………………………………创建invoker……………………………………………………………………………………………… */
              //从channel获取port,从invocation获取服务path,serviceKey=path:port,然后exporterMap.get(serviceKey).getInvoker获取服务的invoker
                Invoker<?> invoker = getInvoker(channel, inv);
              
                //如果是callback 需要处理高版本调用低版本的问题
                if (Boolean.TRUE.toString().equals(inv.getAttachments().get(IS_CALLBACK_SERVICE_INVOKE))){ //2 
                    String methodsStr = invoker.getUrl().getParameters().get("methods");
                    boolean hasMethod = false;
                  
                    if (methodsStr == null || methodsStr.indexOf(",") == -1){//3 
                        hasMethod = inv.getMethodName().equals(methodsStr);
                    } else {
                        String[] methods = methodsStr.split(",");
                        for (String method : methods){//4
                            if (inv.getMethodName().equals(method)){
                                hasMethod = true;
                                break;
                            }
                        } //4 
                    }//3
                  
                    if (!hasMethod){
                        logger.warn(new IllegalStateException("The methodName "+inv.getMethodName()+" not found in callback service interface ,invoke will be ignored. please update the api interface. url is:" + invoker.getUrl()) +" ,invocation is :"+inv );
                        return null;
                    }
                } //2
/**……………………………………………… RpcContext.getContext()获取threadLocal线程变量,并将remote的客户端地址存入……………………………………………… */
                RpcContext.getContext().setRemoteAddress(channel.getRemoteAddress());
/** ……………………………………………………………………………………………invoker.invoke(invocation)调用服务……………………………………………………………………………………*/
                return invoker.invoke(inv);
            } //1
            throw new RemotingException(channel, "Unsupported request: " + message == null ? null : (message.getClass().getName() + ": " + message) + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress());
        }

  			//接收信息
        @Override
        public void received(Channel channel, Object message) throws RemotingException {
            if (message instanceof Invocation) {
                reply((ExchangeChannel) channel, message);
            } else {
                super.received(channel, message);
            }
        }

        @Override
        public void connected(Channel channel) throws RemotingException {
          //在connected连接时,调用invoker方法,其methodKey为onConnect
            invoke(channel, Constants.ON_CONNECT_KEY);
        }

        @Override
        public void disconnected(Channel channel) throws RemotingException {
            if(logger.isInfoEnabled()){
                logger.info("disconected from "+ channel.getRemoteAddress() + ",url:" + channel.getUrl());
            }
            //在disconnected断开连接时,调用invoker方法,其methodKey为onDisconnect
            invoke(channel, Constants.ON_DISCONNECT_KEY);
        }
        
  			//调用服务
        private void invoke(Channel channel, String methodKey) {
            Invocation invocation = createInvocation(channel, channel.getUrl(), methodKey);//构建invocation
            if (invocation != null) {
                try {
                    received(channel, invocation);
                } catch (Throwable t) {
                    logger.warn("Failed to invoke event method " + invocation.getMethodName() + "(), cause: " + t.getMessage(), t);
                }
            }
        }
        
  			//根据client端请求,创建调用的invocation信息
        private Invocation createInvocation(Channel channel, URL url, String methodKey) {
            String method = url.getParameter(methodKey);
            if (method == null || method.length() == 0) {
                return null;
            }
            RpcInvocation invocation = new RpcInvocation(method, new Class<?>[0], new Object[0]);
            invocation.setAttachment(Constants.PATH_KEY, url.getPath());
            invocation.setAttachment(Constants.GROUP_KEY, url.getParameter(Constants.GROUP_KEY));
            invocation.setAttachment(Constants.INTERFACE_KEY, url.getParameter(Constants.INTERFACE_KEY));
            invocation.setAttachment(Constants.VERSION_KEY, url.getParameter(Constants.VERSION_KEY));
            if (url.getParameter(Constants.STUB_EVENT_KEY, false)){
                invocation.setAttachment(Constants.STUB_EVENT_KEY, Boolean.TRUE.toString());
            }
            return invocation;
        }
    };

仔细看该ExchangeHandlerAdapter类,其内定义了在client端发来请求时,provider通过创建invoker,来实现调用服务的逻辑。

image-20230313123836364
CONN2 Exchangers.connect(url, requestHandler)

Exchangers是exchange层门面类。跟入connect连接:

public class Exchangers {

public static ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
if (url == null) {
    throw new IllegalArgumentException("url == null");
}
if (handler == null) {
    throw new IllegalArgumentException("handler == null");
}
  //加入CODEC_KEY:exchange的url上的参数对
url = url.addParameterIfAbsent(Constants.CODEC_KEY, "exchange");
//CONN2.1 getExchanger(url)
//CONN2.2 HeaderExchanger.connect(url,handler)
  // SPI加载,获取 Exchange 实例,默认为 HeaderExchanger
return getExchanger(url).connect(url, handler);
}
//CONN2.1 getExchanger(url)--HeadExchanger
 public static Exchanger getExchanger(URL url) {
      //Exchanger类型为header
    String type = url.getParameter(Constants.EXCHANGER_KEY, Constants.DEFAULT_EXCHANGER);
    return getExchanger(type);
}

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

创建HeadExchanger。

//CONN2.2 HeaderExchanger.connect(url,handler)
public class HeaderExchanger implements Exchanger {
    
  	//connect创建客户端
    public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
//CONN2.2.1 new DecodeHandler(new HeaderExchangeHandler(handler))
//CONN2.2.2 Transporters.connect(url,handler)
    // 这里包含了多个调用,分别如下:
    // 1. 创建 HeaderExchangeHandler 对象
    // 2. 创建 DecodeHandler 对象
    // 3. 通过 Transporters 构建 Client 实例
    // 4. 创建 HeaderExchangeClient 对象
    return new HeaderExchangeClient(Transporters.connect(url, new DecodeHandler(new HeaderExchangeHandler(handler))), true);}
//CONN2.2.1 new DecodeHandler(new HeaderExchangeHandler(handler))--handler处理链(同provider端)

这里构造netty上的channelHandler的处理链,过程和provider端的过程相同,略。

从上述过程,可知是对channelHandler的链式包装,构成handler处理链。

image-20221219200740990

各个handler的作用:

HeaderExchangeHandler主要还是管理连接等。
DecodeHandler主要是对请求进行解码。

image-20221231162316193

//CONN2.2.2 Transporters.connect(url,handler)-->创建NettyClient
public class Transporters {
    
    //通过 Transporters 构建 Client 实例
    public static Client connect(URL url, ChannelHandler... handlers) throws RemotingException {
    if (url == null) {
        throw new IllegalArgumentException("url == null");
    }
    ChannelHandler handler;
    if (handlers == null || handlers.length == 0) {
      //handler为channel.pipeline上事件处理器,定义了一系列inbound和outbound事件触发方法
        handler = new ChannelHandlerAdapter();
    } else if (handlers.length == 1) {
        handler = handlers[0];
    } else {
        // 如果 handler 数量大于1,则创建一个 ChannelHandler 分发器
        handler = new ChannelHandlerDispatcher(handlers);
    }
    // 获取 Transporter 自适应拓展类Transporter@Adaptive,并调用 connect 方法生成 Client 实例
    return getTransporter().connect(url, handler);
    }
    
    public static Transporter getTransporter() {
        return ExtensionLoader.getExtensionLoader(Transporter.class).getAdaptiveExtension();
    }
public class NettyTransporter implements Transporter {
    public Client connect(URL url, ChannelHandler listener) throws RemotingException {
    // 创建 NettyClient 对象
    return new NettyClient(url, listener);
    }
总结:DubboProtocol.refer构建invoker流程
image-20230313123912967

总结:

1 consumer端,DubboProtocol.refer创建的是DubboInvoker的实例,在init初始化构建后,底层有NettyClient的客户端,具备远程通信功能;

2 ExchangeClient没有通信能力,需要对底层NettyClient层层封装;

3 DubboProtocol中,refer方法创建一个DubboInvoker实例,每次创建实例加入invokers的集合中。

posted @ 2023-03-13 14:47  LeasonXue  阅读(31)  评论(0编辑  收藏  举报