Dubbo服務調用過程

在這裏插入圖片描述
引用

在這裏插入圖片描述

refer

根據遠端服務的接口serviceType和服務地址信息url創建RPC代理

public <T> Invoker<T> refer(Class<T> serviceType, URL url) throws RpcException {
    optimizeSerialization(url);
    // create rpc invoker.
    DubboInvoker<T> invoker = 
        new DubboInvoker<T>(serviceType, url, getClients(url), invokers);
    invokers.add(invoker);
    return invoker;
}

創建客戶端

通過一頓設計模式的操作,由HeaderExchanger調用NettyTransporter創建一個NettyClient

/**
 * 通過netty創建url連接的客戶端
 * @see NettyClient#open()
 */
client = Exchangers.connect(url, requestHandler);
/**
 * @see AbstractClient#AbstractClient(URL, ChannelHandler) AbstractClient的構造方法中調用doOpen
 */
@Override
protected void doOpen() throws Throwable {
    NettyHelper.setNettyLoggerFactory();
    bootstrap = new ClientBootstrap(channelFactory);
    // config
    // @see org.jboss.netty.channel.socket.SocketChannelConfig
    bootstrap.setOption("keepAlive", true);
    bootstrap.setOption("tcpNoDelay", true);
    bootstrap.setOption("connectTimeoutMillis", getConnectTimeout());
    // nettyClient(繼承鏈中的AbstractPeer)作爲requestHandler的代理類 自己作爲ChannelHandler
    final NettyHandler nettyHandler = new NettyHandler(getUrl(), this);
    bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
        @Override
        public ChannelPipeline getPipeline() {
            NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyClient.this);
            ChannelPipeline pipeline = Channels.pipeline();
            pipeline.addLast("decoder", adapter.getDecoder());
            pipeline.addLast("encoder", adapter.getEncoder());
            pipeline.addLast("handler", nettyHandler);
            return pipeline;
        }
    });
}

Invoker

org.apache.dubbo.rpc.protocol.AbstractInvoker的子類 (默認實現Dubbo)

invoker保存了這個rpc調用所需信息(url、接口類)和網絡資源(NettyClient)

一個invoker對應多個client,表示一個服務有多個服務提供地址

private final ExchangeClient[] clients;

// balabala
// 輪詢策略
if (clients.length == 1) {
    currentClient = clients[0];
} else {
    currentClient = clients[index.getAndIncrement() % clients.length];
}

doInvoke

doInvoke方法不同協議的遠程調用實現,默認實現爲dubbo

由Proxy代理實例調用doInvoke,與服務提供方進行數據交互

/**
 * 基於dubbo協議的遠程調用實現
 * @param invocation 遠程調用信息封裝
 */
@Override
protected Result doInvoke(final Invocation invocation) throws Throwable {
    RpcInvocation inv = (RpcInvocation) invocation;
    final String methodName = RpcUtils.getMethodName(invocation);
    inv.setAttachment(Constants.PATH_KEY, getUrl().getPath());
    inv.setAttachment(Constants.VERSION_KEY, version);

    ExchangeClient currentClient;
    if (clients.length == 1) {
        currentClient = clients[0];
    } else {
        currentClient = clients[index.getAndIncrement() % clients.length];
    }
    try {
        boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);
        boolean isAsyncFuture = RpcUtils.isGeneratedFuture(inv) || RpcUtils.isFutureReturnType(inv);
        boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
        int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
        if (isOneway) {
            boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
            // 阻塞請求
            currentClient.send(inv, isSent);
            RpcContext.getContext().setFuture(null);
            return new RpcResult();
        } else if (isAsync) {
            // 異步請求
            ResponseFuture future = currentClient.request(inv, timeout);
            // For compatibility
            FutureAdapter<Object> futureAdapter = new FutureAdapter<>(future);
            RpcContext.getContext().setFuture(futureAdapter);

            Result result;
            if (isAsyncFuture) {
                // register resultCallback
                result = 
                    new AsyncRpcResult(futureAdapter, futureAdapter.getResultFuture(), false);
            } else {
                result = 
                    new SimpleAsyncRpcResult(futureAdapter, futureAdapter.getResultFuture(), false);
            }
            return result;
        } else {
            RpcContext.getContext().setFuture(null);
            return (Result) currentClient.request(inv, timeout).get();
        }
    } catch (TimeoutException e) {
        throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
    } catch (RemotingException e) {
        throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
    }
}

Proxy.getProxy.newInstance

根據invoker中的信息,創建RPC的本地代理實例(instance),供業務層調用(作爲Component存入Spring容器中)

獲取proxy

Proxy.getProxy 靜態方法

根據服務的接口類生成代理類的class對象 extends Proxy implements serviceInterface

<T> T getProxy(Invoker<T> invoker) throws RpcException;

Proxy.getProxy(ClassLoader cl, Class<?>... ics) javassist實現

構造函數

getProxy爲生成的所有代理類添加一個InvocationHandler的私有變量和構造函數

ccp.addField("private " + InvocationHandler.class.getName() + " handler;");
ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]{InvocationHandler.class}, new Class<?>[0], "handler=$1;");

後面newInstance方法中,就是調用這個構造方法,new出來的代理對象

方法列表

javassist動態生成的代理的方法

  • 服務接口的方法
  • newInstance(handler)

自動生成的實現代碼示例

public String interfaceMethodName($1){
    Object[] args = new Object[1]; 
    args[0] = ($w)$1; 
    Object ret = handler.invoke(this, methods[2], args); 
    return (java.lang.String)ret;
}

獲取代理實例

proxy.newInstance(handler) 實例方法

在創建實例時將上面創建負責發起遠端請求的invoker封裝成handler注入到代理實例中;在調用實例方法時,會將調用方法轉成invocation,將rpc調用的結果Result

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章