ダボソースの深さ - とSPIを使用する利点

免責事項:この記事はブロガーオリジナル記事です、続くBY-SAのCC 4.0を著作権契約、複製、元のソースのリンクと、この文を添付してください。
このリンク: https://blog.csdn.net/red_sheeps/article/details/100854469

背景

私は学生のソースは、インターフェイスの多くがいる見るべきダボダボを読んで信じて@SPI、著者は例外ではありませんコメントを、しかし、この注釈は、問題を解決するために、どのように使用するかを具体的に知りませんでしたか?単純な検索オンライン、中国名:サービス・デリバリー・インターフェースは、(Baiduの百科事典から)次の図を参照してください。
ここに画像を挿入説明
おそらくので、dubbo機能自体は強力ですので、私はそれだけでは、することができます知っているdubboなど、ロードバランシング、シリアライズ、スレッドプールのタイプ、などの特定のポリシーを、達成するためにカスタマイズすることではなく、まだ正式にオンライン環境を持っています。休日、次のレコードを利用することで、勉強する時間をかけて、便利になりたいです。

サンプルコード

以下のコードをノックするために、ローカル、純粋に手によって検証され、具体的な実装が見栄光ののGitHub
注:テストプロジェクトをビルドするためにspring-boot+ 春ブーツ、ダボ

アイデアを確認してください

図形が属するようにと言った、@SPI特定のサービスを実現するために、負荷分散(より最も身近達成する簡単であろうLoadBalance)戦略、ローカル開始2つのproviderを介して、異なるポートconsumerで指定されたアクセスパラメータを決定しますA provider

プロバイダを開始します

非常に簡単なコード、コードはフレームを次の
ここに画像を挿入説明

import org.apache.dubbo.config.annotation.Service;
import org.apache.dubbo.rpc.RpcContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

// 指定版本和分组
@Service(version = "1.0.0",group = "glory")
public class DemoServiceImpl implements DemoService {
    private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);

    @Override
    public String sayHello(Integer port) {
        logger.info("Hello " + port + " request from consumer: " + RpcContext.getContext().getRemoteAddress());
        return "Hello ,"+port+" response from provider: " + RpcContext.getContext().getLocalAddress();
    }

}

以下は、application.yml設定ファイル

server:
  port: 8083
dubbo:
  application:
    name: dubbo-common-provider
  scan:
    base-packages: com.redsun.rpc.dubbo
  protocol:
    name: dubbo
    port: 12345
  registry:
    address: zookeeper://127.0.0.1:2181

また、あなたが起動しないでか、起動時に別のポートを指定する必要があることに注意してください。
ここに画像を挿入説明
この時点では、効果を開始し、通常の2つのローカルアプリケーションを起動することができ、次のとおりです。
ここに画像を挿入説明

消費者を開始

consumerコードはまた、非常にシンプルなフレームワークである
ここに画像を挿入説明
、確かに我々は推測推測できるGloryLoadBalance前面から渡されたパラメータを選択するための独自のを達成するための戦略をロードバランシングの一種であり、invoker

public class GloryLoadBalance implements LoadBalance {

    private static final Logger logger = LoggerFactory.getLogger(GloryLoadBalance.class);

    @Override
    public <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {
        Integer port = (Integer) invocation.getArguments()[0];// 前端传入的参数
        logger.info("前端传入端口为:" + port);
        // java8的流式编程,有兴趣的同学可以研究下,后续会再专门写一篇
        Invoker<T> invokerRet = invokers.stream().filter(invoker -> invoker.getUrl().getPort() == port).findFirst().get();
        return invokerRet == null ? invokers.get(0) : invokerRet;
    }
}

ここにも書いた簡単なcontroller動的パラメータを変更することが、簡単に

@RestController
@RequestMapping("/admin")
public class AdminController {
    private static final Logger logger = LoggerFactory.getLogger(AdminController.class);

    @Reference(version = "1.0.0",group = "glory", loadbalance = "glory")
    private DemoService demoService;

    @RequestMapping("/invoke")
    public String invoke(@RequestParam(name = "port") Integer port) {
        logger.info("invoke method be invoked!port = " + port);
        return demoService.sayHello(port);
    }
}

もちろん、最後のステップになります、そして最も重要なのは、META-INF.dubbo.internal追加のプロファイルディレクトリの前に等号以下のgloryあなたが設定されているという事実loadbalanceキーを、そしてパスが間違っているか、設定されていない場合は、まだデフォルトの実装になりますrandom

glory=com.redsun.rpc.dubbo.loadbalance.GloryLoadBalance

dubboロードされMETA-INF.dubbo.internalたディレクトリ内のすべての設定情報を、dubboディレクトリは、デフォルトの実装の多くになります
ここに画像を挿入説明

郵便配達の呼び出し

以下の二つのグラフは、期待に応えるためにテスト。
ここに画像を挿入説明
ここに画像を挿入説明

ソース

ここでは、ソースコードをオンにする時間だ、と私はその経験のソースコードをシンプルな外観について話すためにここにいます。

  • 通常でデバッグ、各メソッドの実装にもつれないでください、それはハローと簡単で、そして最終的に興味を失いました
  • オープンソース以来、私が書かれている通常と異なっている、それはすべてのためにアクセス可能であるノート、特に、メソッド名、クラス名、変数名、ソースコードを読むことを学び、それはノート、しばしば非常に非常に詳細仕様、英語で書かれた名前付き分かりません?翻訳、より頻繁に会いました
  • 全体の呼び出しチェーンを読んだ後、いくつかのコアクラスをデバッグするときに覚えている、あなたが持っているコードの構造が本当に見たくない(認知次のラフなものを持っているために、Baiduはまた、私は頻繁にして、それを行いますその後、証明書の下で、自分自身を見て)

ロード

拡張ローダー#getExtensionClasses

    // synchronized in getExtensionClasses
    private Map<String, Class<?>> loadExtensionClasses() {
        cacheDefaultExtensionName();

        Map<String, Class<?>> extensionClasses = new HashMap<>();
        loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName());
        loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
        loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName());
        loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
        loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName());
        loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
        return extensionClasses;
    }

ここに画像を挿入説明

    /**
     * put clazz in extensionClasses
     */
    private void saveInExtensionClass(Map<String, Class<?>> extensionClasses, Class<?> clazz, String name) {
        Class<?> c = extensionClasses.get(name);
        if (c == null) {
            // 将扩展类GloryLoadBalance存入map中,最终会将默认提供的几种都存入map中
            extensionClasses.put(name, clazz);
        } else if (c != clazz) {
            throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + name + " on " + c.getName() + " and " + clazz.getName());
        }
    }

負荷クラスは、最終的に達成する優れたReferenceConfig負荷分散パラメータがに設定されていますglory
ここに画像を挿入説明

ラン

AbstractClusterInvoker番号の呼び出し

consumer起動invokeキーの時間を設定への選択的係るインスタンスを作成することになります

    public Result invoke(final Invocation invocation) throws RpcException {
        checkWhetherDestroyed();

        // binding attachments into invocation.
        Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
        if (contextAttachments != null && contextAttachments.size() != 0) {
            ((RpcInvocation) invocation).addAttachments(contextAttachments);
        }

        List<Invoker<T>> invokers = list(invocation);
        // 初始化加载负载均衡类
        LoadBalance loadbalance = initLoadBalance(invokers, invocation);
        RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
        return doInvoke(invocation, invokers, loadbalance);
    }

拡張ローダー#getExtensionLoader

META-INF.dubbo.internalディレクトリ内のファイルは、ExtensionLoader静的クラス変数に格納されているオブジェクトEXTENSION_LOADERS

    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        if (type == null) {
            throw new IllegalArgumentException("Extension type == null");
        }
        if (!type.isInterface()) {
            throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
        }
        // 此处判断是否以SPI注解修饰
        if (!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type (" + type +
                    ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
        }

        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        if (loader == null) {
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
        return loader;
    }

拡張ローダー#getExtension

この時間が空の場合は、上記のクラスのnewInstance、コードをロードすることにより、情報の使用例は比較的簡単ですが、興味はについて話すことができます。
ここに画像を挿入説明

概要

あなたは(対応するインタフェースを実装)実装クラスを高めるために、非常にシンプルになりますダボフォローアップの利用を拡大したい場合は、上記の、見られるべきであるし、その後でMETA-INF、設定ファイルのディレクトリを追加し、良いの鍵と対応を行うことができます。シリアル化はまた、彼らの願いに従うことができます。
コードが使用されていないいくつかの他の拡張クラスで見ることができる場合、ダボがクラスオブジェクトにロードされ、それは、それ小さな欠陥の少し考えることができます。

おすすめ

転載: blog.csdn.net/red_sheeps/article/details/100854469