Dubboのリモートコールバック

4203 ワード

Dubboが消費者としてNettyServerを介して対応するサービスの送信要求を呼び出す準備をしている場合は、まずNettyCodeAdapterを介して具体的なデータを符号化する.
符号化の過程で,消費者が対応するパラメータを呼び出した方法でリモートコールバックが必要か否かを判断するために,方法中のパラメータを巡回する.
判断の根拠は,消費者がリモートコールを必要とするメソッドのパラメータを組み立てる際に,コールバックを必要とするメソッドのうちの幾つか目のパラメータを配置し,生産者はそのメソッドの幾つか目のパラメータのcallBack属性に基づいてコールバックを必要とするか否かを判断し,このパラメータのurlにおける形式はmethodName.いくつかのパラメータcallBack.
private static byte isCallBack(URL url, String methodName, int argIndex) {
    // parameter callback rule: method-name.parameter-index(starting from 0).callback
    byte isCallback = CALLBACK_NONE;
    if (url != null) {
        String callback = url.getParameter(methodName + "." + argIndex + ".callback");
        if (callback != null) {
            if (callback.equalsIgnoreCase("true")) {
                isCallback = CALLBACK_CREATE;
            } else if (callback.equalsIgnoreCase("false")) {
                isCallback = CALLBACK_DESTROY;
            }
        }
    }
    return isCallback;
}

このパラメータに基づいてコールバックが必要かどうかを確認します.
生産者が対応するパラメータの呼び出しをリモートコールバックする必要があると判断した場合,生産者と同様に対応するコールバック方法を暴露する必要がある.
private static String exportOrunexportCallbackService(Channel channel, URL url, Class clazz, Object inst, Boolean export) throws IOException {
    int instid = System.identityHashCode(inst);

    Map params = new HashMap(3);
    // no need to new client again
    params.put(Constants.IS_SERVER_KEY, Boolean.FALSE.toString());
    // mark it's a callback, for troubleshooting
    params.put(Constants.IS_CALLBACK_SERVICE, Boolean.TRUE.toString());
    String group = url.getParameter(Constants.GROUP_KEY);
    if (group != null && group.length() > 0) {
        params.put(Constants.GROUP_KEY, group);
    }
    // add method, for verifying against method, automatic fallback (see dubbo protocol)
    params.put(Constants.METHODS_KEY, StringUtils.join(Wrapper.getWrapper(clazz).getDeclaredMethodNames(), ","));

    Map tmpmap = new HashMap(url.getParameters());
    tmpmap.putAll(params);
    tmpmap.remove(Constants.VERSION_KEY);// doesn't need to distinguish version for callback
    tmpmap.put(Constants.INTERFACE_KEY, clazz.getName());
    URL exporturl = new URL(DubboProtocol.NAME, channel.getLocalAddress().getAddress().getHostAddress(), channel.getLocalAddress().getPort(), clazz.getName() + "." + instid, tmpmap);

    // no need to generate multiple exporters for different channel in the same JVM, cache key cannot collide.
    String cacheKey = getClientSideCallbackServiceCacheKey(instid);
    String countkey = getClientSideCountKey(clazz.getName());
    if (export) {
        // one channel can have multiple callback instances, no need to re-export for different instance.
        if (!channel.hasAttribute(cacheKey)) {
            if (!isInstancesOverLimit(channel, url, clazz.getName(), instid, false)) {
                Invoker> invoker = proxyFactory.getInvoker(inst, clazz, exporturl);
                // should destroy resource?
                Exporter> exporter = protocol.export(invoker);
                // this is used for tracing if instid has published service or not.
                channel.setAttribute(cacheKey, exporter);
                logger.info("export a callback service :" + exporturl + ", on " + channel + ", url is: " + url);
                increaseInstanceCount(channel, countkey);
            }
        }
    } else {
        if (channel.hasAttribute(cacheKey)) {
            Exporter> exporter = (Exporter>) channel.getAttribute(cacheKey);
            exporter.unexport();
            channel.removeAttribute(cacheKey);
            decreaseInstanceCount(channel, countkey);
        }
    }
    return String.valueOf(instid);
}

ここでは,消費者のアドレスに基づいて,直接接続urlを構築してリモートコールバックの必要性を達成した.その後,他のサービスと同様にエージェントを構築し,DubboProtocolのexport()メソッドにより暴露する.得られたexporterをvalueとし、パラメータのhashcodeによってkeyを構築し、キー値ペアを構成してchannelに格納し、生産者が要求を受信した後、keyに基づいてchannelで対応するexporterを得ることができることを保証し、エージェントの作成を完了し、リモートコールバックの機能を完了させる.