JavaのSPIとその実施メカニズム

序文

最初のコンタクトSPIは、JDBCの関連セクションで、「Javaのコア・コンピューティング・ボリューム」を見ているとき、我々はそれは、JDBCの高いバージョンによって省略することができる参照Class.forNameSPIメカニズムによって自動的ので、JDBCの高いバージョンのこのステップをロードするためのドライバ登録ドライブをロードします。

その時、私は見て非常に嬉しい驚きを感じたときに、最終的に私は長くて退屈記述する必要はありませんtry-catch

その後、ソースコードを読み取る過程で、彼はまた、春のJava SPIはまた、機能の類似したメカニズム、いくつかの研究を達成し、使用中または実施中のいずれかのSPIメカニズムは非常に単純で見つかったことがわかりました。

だから、私はあなたが全体のブログの記事をまとめることができると思います。

非表示コンテンツ 前回少しShoushengの@を感じブログまたはNo 6月22日、ダウン100日以上、\ _ @

ServiceLoader

SPI(サービスプロバイダインタフェース)の完全な名前は、組み込みのJDK提供するサービスディスカバリメカニズムです。これは、ツールで構成されjava.util.ServiceLoader、適切なサポートを提供します。

二つの主要な役割のひとつ:

  • サービス - サービスは、通常、インターフェースや抽象クラスとして、それが具体的なクラスをすることができるが、一般的にはそうすることをお勧めしません
  • サービスプロバイダ - サービスプロバイダ、サービス実装クラス

使用の際には、必要性META-INF/servicesの作成とサービスの低下は、完全修飾された同じファイルをし、文書の中に記述し、サービスプロバイダの完全修飾名を使用することができます#コメントとして。例えば、我々は提出できmysql-connector-java/META-INF/services/java.sql.Driver、次で見つかりました:

com.mysql.jdbc.Driver
com.mysql.fabric.jdbc.FabricMySQLDriver

その後、次のことができますServiceLoaderこれらのサービスプロバイダを取得します。ServiceLoader方式は、サービス・プロバイダーへの直接アクセスを提供していないので、それゆえ、唯一の反復的な方法によって得ることができます。

ServiceLoader<Service> loader = Service.load(Service.class);

for (Service service : loader) {
  // ...
}

:あなたが見ることができる、ServiceLoaderは、より関連性の高いコンテンツを使用することは非常に簡単で、ServiceLoaderは、公式ドキュメントを見ることができますServiceLoader(JavaプラットフォームSE 8)

使用JDBC

あなたはSPI機構の使用例を探している場合は、ドライバをロードするSPIによって、JDBCの最も直接的な方法であり、ここでは、JDBCの使用を見ることができます。

public class DriverManager {
  static {
    loadInitialDrivers();
  }

  private static void loadInitialDrivers() {
    AccessController.doPrivileged(new PrivilegedAction<Void>() {
        public Void run() {

          ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
          Iterator<Driver> driversIterator = loadedDrivers.iterator();

          try{
            while(driversIterator.hasNext()) {
              driversIterator.next();
            }
          } catch(Throwable t) {
            // Do nothing
          }
          return null;
        }
      });
  }
}

上記の簡略化した後のコードにより求めることができる、負荷にDriverManager静的場合クラスコードブロックによって実行される初期化と呼ばれるloadInitialDriversことによって方法、及びこの方法の意志をServiceLoader全てロードDriverプロバイダ。

ドライバは、ベースとして、各クラス内に設けられたcom.mysql.jdbc.Driverフォームのコードの有無:

static {
  try {
    java.sql.DriverManager.registerDriver(new Driver());
  } catch (SQLException E) {
    throw new RuntimeException("Can't register driver!");
  }
}

それは単純ではないですか?SPIを介して各ドライバのDriverManagerローディング機構をロードし、次にそれぞれのドライバに独自の静的初期化子ブロックDriverManagerは自身を登録する場合。

より多くの利用シナリオ

SPIを使用するために、JDBC SPIメカニズムを使用することによって見つけることができる、それは非常にシンプルなので、私たちは場所にSPIを使用することができますか?

単一ServiceLoaderの制限によるSPIメカニズムは、サービスの単一のタイプを読み込むことができますが、またに適切なファイルを作成する必要がありMETA-INF/servicesますが、単一のオブジェクトが提供する他のサービスにアクセスすることができますので、最善のシナリオは、この中にJDBCに似て使用して、ディレクトリこれらのシーンは、すなわち:あなたが使用することができファサードパターンのシーンを。

例えば、今などGson、FastJSON、ジャクソン、など、多くの一般的に使用されるJavaのJSONライブラリは、ありますが、これらのライブラリは、パッケージの単純過半数のニーズを満たすために使用することができ、その後、我々はSPIでのメカニズムを考慮することができますこれらのJSONライブラリのファサードを達成するため、完了するために、治療JSONサービスプロバイダの下に置く、と私たちは、ファサードを介してこれらのサービスを使用します。

その結果、私たちは自分のデフォルトの実装を提供することができるが、それはまた、拡張可能なインターフェイスを残すことができ、手動で達成したものにロードする必要はありません。

原則

SPIは使用されていないだけで非常に簡単で、その実装の原理は、内のキーは非常にシンプルであるClassLoader.getResourcesこの方法では、SPIのロードサービスを介してであるClassLoader.getResources方法を見つけるためにMETA-INF/servicesディレクトリ内のファイルに対応し、[サービスプロバイダのクラス名を取得するためにファイルを解析。

最後に、Class.forName() -> clazz.newInstance()返されたインスタンスを取得します。

非常にシンプルで簡単な実装、より注目されるClassLoader.getResources方法を使用することは、あなたが一つにすることができ、例えば、Spring次のコードの下でプロジェクトの実施:

public class Test {
  public static void main(String[] args) throws Exception {
    Enumeration<URL> urls = Test.class.getClassLoader().getResources("META-INF/spring.factories");
    while (urls.hasMoreElements()) {
      System.out.println(urls.nextElement());
    }
  }
}

これはで春ですSpringFactoriesLoader関連するクラスをロードするための出発点。

SpringFactoriesLoader

SpringFactoriesLoader春は非常に重要な拡張メカニズムの一つであり、原則とSPIの使用と実装は非常に似ていますが、より強力な機能を提供します。

SPIと異なる、SpringFactoriesLoaderコンフィギュレーション・ファイル・フォーマットであるためproperties、ファイルが、そうでする必要はありませんが、SPIなどの各サービスのファイルを作成するのではなく、すべてのサービスがに投げている指揮することを選択したMETA-INF/spring.factoriesファイル。

例えば、一部のスプリング・ブート自動構成:

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnClassCondition

# ...

参照することができ、より使用:SpringFactoriesLoader(5.2.0.RELEASE SpringフレームワークのAPI)

エピローグ

全体的に、ServiceLoaderまたはSpringFactoriesLoader両方が、彼らの基本的な原理は同じであるが、を介して行われClassLoader.getResources、適切なコンフィギュレーションファイルの方法を見つけ、その後、サービスプロバイダの完全修飾名を取得するには、ファイルを解析します。

強力なJavaリフレクション機構の恩恵で、何を行うことができます基本的には完全修飾名を取得するには@ _ @

非表示コンテンツ

JSONみすぼらしいファサード:DefaultJsonProviderFactory.java

おすすめ

転載: www.cnblogs.com/rgbit/p/11627434.html