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); } |