ホームページ >Java >&#&チュートリアル >SpringBootのSPIメカニズムを実装する方法
SPI (Service Provider Interface) は、JDK に組み込まれたサービス検出メカニズムであり、フレームワークの拡張機能やコンポーネントの置き換えを可能にするために使用できます。 Dubbo、Spring、Common-Logging、JDBC などのフレームワークでの開発では、SPI メカニズムを使用して、同じインターフェイスの異なる実装を異なるユーザーに提供し、フレームワークのスケーラビリティを向上させます。
Java の組み込み SPI は、java.util.ServiceLoader クラスを使用して、classPath および META-INF/services/ 内のインターフェイスの完全修飾名で指定されたファイルを解析します。 jar パッケージのディレクトリを指定し、ファイル内で指定されたインターフェイス実装クラスをロードして呼び出しを完了します。
public interface VedioSPI { void call(); }
public class Mp3Vedio implements VedioSPI { @Override public void call() { System.out.println("this is mp3 call"); } }
public class Mp4Vedio implements VedioSPI { @Override public void call() { System.out.println("this is mp4 call"); } }
ソース ディレクトリ内プロジェクト 新しい META-INF/services/ ディレクトリに com.skywares.fw.juc.spi.VedioSPI ファイルを作成します。
public class VedioSPITest { public static void main(String[] args) { ServiceLoader<VedioSPI> serviceLoader =ServiceLoader.load(VedioSPI.class); serviceLoader.forEach(t->{ t.call(); }); } }
説明: Java は、ServiceLoader を介して spi を実装し、サービスによって提供されるツール クラスを見つけます。
上記は、Java の組み込み SPI 関数を実装する簡単な例にすぎません。実装原理としては、ServiceLoader はサービス提供インターフェースを見つけるための組み込み Java ツールクラスであり、load() メソッドを呼び出してサービス提供インターフェースを検索し、最後にサービス提供インターフェースの実装クラスを 1 つずつトラバースしてアクセスします。 。
ソース コードから見つけることができます:
ServiceLoader クラス自体は Iterable インターフェイスを実装し、次の iterator メソッドを実装します。 it. iterator メソッド 内部クラス LazyIterator のメソッドが実装で呼び出されます. サービス プロバイダー インターフェイス ファイルを解析した後、最終結果が Iterator に配置されて返されます. サービス プロバイダー インターフェイス実装クラスへの直接アクセスはサポートされていません.
すべてのサービス プロバイダー インターフェイスに対応するファイルは、META-INF/services/ ディレクトリに配置され、最後のタイプにより、PREFIX ディレクトリを変更できないことが決定されます。
Java が提供する SPI メカニズムのアイデアは非常に優れていますが、相応の欠点もあります。詳細は次のとおりです。
Java の組み込みメソッドはトラバーサルを通じてのみ取得できます
サービス プロバイダー インターフェイスは META に配置する必要があります-INF/サービス/ コンテンツの下。
Java の SPI に存在する問題を考慮して、Spring の SPI メカニズムは SPI の考え方に従いながら、それを拡張し、最適化しています。
Spring SPI は、Java SPI の設計思想に従っています。Spring は、spring.factories メソッドを使用して SPI メカニズムを実装し、Spring ソースを変更せずに Spring フレームワークを提供できます。コード、スケーラビリティ。
Spring の例
定義インターフェイス
public interface DataBaseSPI { void getConnection(); }
関連実装
#DB2实现 public class DB2DataBase implements DataBaseSPI { @Override public void getConnection() { System.out.println("this database is db2"); } } #Mysql实现 public class MysqlDataBase implements DataBaseSPI { @Override public void getConnection() { System.out.println("this is mysql database"); } }
1. プロジェクトの META-INF ディレクトリに、 spring.factories ファイルを追加します。
2. 関連するインターフェイス情報を入力します。内容は次のとおりです。
com.skywares.fw.juc.springspi.DataBaseSPI = com.skywares.fw .juc.springspi.DB2DataBase、com.skywares.fw.juc.springspi.MysqlDataBase
説明 複数の実装はカンマで区切られます。
関連テストクラス
public class SpringSPITest { public static void main(String[] args) { List<DataBaseSPI> dataBaseSPIs =SpringFactoriesLoader.loadFactories(DataBaseSPI.class, Thread.currentThread().getContextClassLoader()); for(DataBaseSPI datBaseSPI:dataBaseSPIs){ datBaseSPI.getConnection(); } } }
出力結果
この例から、Spring が spring.factories を使用して SPI と Java を実装していることがわかります。実装 SPI は非常に似ていますが、Java の spi に対する Spring の spi メソッドの最適化は次のとおりです。
Java SPI は、設定ファイルに対応するインターフェイスを提供するサービスであり、設定ファイル現在のインターフェイスのすべての実装クラスを保存します。複数のサービス プロバイダー インターフェイスは複数の設定ファイルに対応し、すべての設定はサービス ディレクトリにあります。
Spring Factory SPI は spring.factories 設定ファイルです。複数のインターフェイスと対応する実装クラスは、キーとしてインターフェイスの完全修飾名、値として実装クラスを使用して設定されます。複数の実装クラスはカンマで区切られます。設定ファイルは spring.factories の 1 つだけです。
では、spring.factories をロードすることで、Spring はどのように SpI を実装するのでしょうか? ソース コードを通じてさらに分析できます。
説明:loadFactoryNames は、spring.factories ファイル内の指定されたインターフェイスの実装クラスの完全修飾名を解析します。以下のとおりであります: #### ########
説明: すべての jar パッケージ内の META-INF/spring.factories のファイル パスを取得し、それを列挙値として返します。 spring.factories ファイルのパスをたどり、1 つずつロードおよび解析し、factoryClass 型の実装クラス名を統合し、実装クラスの完全なクラス名を取得して、クラスのインスタンス操作を実行します。関連するソース コードは次のとおりです。
注: インスタンス化は、リフレクションを通じて対応する初期化を実装します。
以上がSpringBootのSPIメカニズムを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。