SPIの原理とAndroidにおけるSPIの実戦

1. 背景

質問を始める前に何か疑問はありますか。つまり、ビジネスの発展と成長に伴い、プロジェクトの構造とコードの量はますます大きくなり、絡み合っています。あなたには私がいます、私には

あなたが真ん中にいると、プロジェクト構造の役割分担があまり明確ではなく、責任も明確ではありません。確認する必要がある緊急の問題がオンライン上にある場合、私たちは急いでいる場合もあれば、そうでない場合もあります。どうやって尋ねればいいのかわからない。

問題はそのモジュールに現れるため、トラブルシューティングの効率が低くなり、プロジェクトのレビューや責任の明確化、または上司がビジネスの成功率やサービスの成功率などのデータを見たいときに役立ちません。

そのとき、便宜上コードに直接記述することがありますが、業務が繰り返し行われると、引き継いだ新しい同僚は頭を悩ませるかもしれません。このコードは正確に何をするのか、またその理由は何でしょうか?

ここに書くべきこと(おそらくこのコードには実際のビジネス上の意味はまったくなく、単に埋められたポイントまたはデータ統計コードです)など、今日はそれを盛大に紹介します。

これらの問題を解決する新しいソリューションを導入します。このソリューションは SPI で、正式名はサービス プロバイダー インターフェイスです。もちろん、他のソリューションがあると言われるかもしれません。はい、確かに

他の計画もあります、すべての道はローマに通じています、わかりました、くだらない話はやめて本題に移りましょう。

2.SPIとは

SPI (Service Provider Interface) は、サードパーティによって実装または拡張されるために JDK によって提供される API のセットであり、JVM レベルでのサービス登録検出メカニズムです。

フレームワーク拡張機能を有効にし、主にフレームワーク開発者によって使用されるコンポーネントを置き換えるために使用できます。SPI メカニズムの主なアイデアは、アセンブリの制御をプログラムの外に移動することです。

このメカニズムは設計において特に重要であり、その中心となる考え方はデカップリングです。

2.1: SPI 全体の仕組み

以下の図 1 に示すように:

図1

Java SPI は実際には、「インターフェイスベースのプログラミング + ストラテジー モード + 設定ファイル」の組み合わせによって実装される動的ローディング メカニズムであり、中心となるアイデアはサービス登録 + サービス検出です。

2.2: SPI と API の違い

これに関しては、多くの人が疑問を持つかもしれません。これと API 呼び出しの違いは何ですか。この問題をより明確に説明するために、具体的な図を使用して説明します。

SPI与API区别:

API

图2所示

图2

SPI

图3所示

图3

一般模块之间通信基本上都是通过接口,那我们在服务调用方和服务实现方(也称服务提供者)之间引入一个“接口概念”。

当实现方提供了接口和实现,我们可以通过调用实现方的接口从而拥有实现方给我们提供的能力,这就是 API ,这种接口和实现都是放在实现方的。

接口和实现方属于同一个模块,密切不可分割。

当接口存在于调用方这边时,就是 SPI ,由接口调用方确定接口规则,然后由不同的具体业务去根据这个规则对这个接口进行实现,从而提供服务,

举个通俗易懂的例子:一个电脑制造公司,设计好了充电器标准图纸以后,那么接下来就可以把这个图纸分发给不同的厂商去生产,最后只有严格按

照图纸要求,就可以生产合格的商品。

通过上面的图2和图3以及配合上面的文字介绍,相信大家应该很非常清楚API和SPI的区别了.

3.SPI作用

SPI的发现能力是不需要依赖于其他类库,主要实现方式是:

  • java.util.ServiceLoader#load JDK自身提供的加载能力

最重要的作用就是:解耦

4.实现原理

4.1: 源码分析

public final class ServiceLoader<S>

implements Iterable<S>

{

//配置文件所在的包目录路径

private static final String PREFIX = "META-INF/services/";

// 接口名称

private final Class<S> service;

// 类加载器

private final ClassLoader loader;

// The access control context taken when the ServiceLoader is created

// Android-changed: do not use legacy security code.

// private final AccessControlContext acc;

//providers就是不同实现类的缓存,key就是实现类的全限定名,value就是实现类的实例

private LinkedHashMap<String,S> providers = new LinkedHashMap<>();

// //内部类LazyIterator的实例

private LazyIterator lookupIterator;

public void reload() {

providers.clear();

lookupIterator = new LazyIterator(service, loader);

}

private ServiceLoader(Class<S> svc, ClassLoader cl) {

service = Objects.requireNonNull(svc, "Service interface cannot be null");

loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;

// Android-changed: Do not use legacy security code.

// On Android, System.getSecurityManager() is always null.

// acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;

reload();

}

private static void fail(Class<?> service, String msg, Throwable cause)

throws ServiceConfigurationError

{

throw new ServiceConfigurationError(service.getName() + ": " + msg,

cause);

}

おすすめ

転載: blog.csdn.net/qq_18757557/article/details/128551981