クラウドネイティブ は、継続的デリバリーと価値主導型開発の分野におけるベストプラクティスの容易な導入を促進するアプリケーション開発のスタイルです。関連する分野として 12 要素アプリケーション (英語) の構築が挙げられます。この分野では、宣言型プログラミングや管理と監視などを使用して、開発実践が配信と運用のゴールに沿って調整されます。Spring Cloud は、さまざまな具体的な方法でこれらの開発スタイルを促進します。開始点は、分散システム内のすべてのコンポーネントに簡単にアクセスできる必要がある一連の機能です。

これらの機能の多くは Spring Boot でカバーされており、その上に Spring Cloud が構築されています。さらにいくつかの機能は、Spring Cloud Context と Spring Cloud Commons という 2 つのライブラリとして Spring Cloud によって提供されます。Spring Cloud コンテキストは、Spring Cloud アプリケーションの ApplicationContext にユーティリティと特別なサービス (ブートストラップコンテキスト、暗号化、リフレッシュスコープ、および環境エンドポイント) を提供します。Spring Cloud Commons は、さまざまな Spring Cloud 実装 (Spring Cloud Netflix や Spring Cloud Consul など) で使用される一連の抽象化と共通クラスです。

「不正なキーサイズ」による例外が発生し、Sun の JDK を使用している場合は、Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction ポリシーファイルをインストールする必要があります。詳細については、次のリンクを参照してください。

使用する JRE/JDK x64/x86 のバージョンに応じて、ファイルを JDK/jre/lib/security フォルダーに抽出します。

Spring Cloud は、制限のない Apache 2.0 ライセンスでリリースされています。ドキュメントのこのセクションに貢献したい場合、またはエラーを見つけた場合は、プロジェクトのソースコードと課題追跡ツールを {docslink}[github] で見つけることができます。

1. Spring Cloud コンテキスト: アプリケーションコンテキストサービス

Spring Boot は、Spring でアプリケーションを構築する方法について独自の見解を持っています。たとえば、共通の構成ファイル用の従来の場所があり、共通の管理および監視タスク用のエンドポイントがあります。Spring Cloud はそ上に構築され、システム内の多くのコンポーネントが使用する、場合によって必要となるいくつかの機能を追加します。

1.1. ブートストラップアプリケーションコンテキスト

Spring Cloud アプリケーションは、メインアプリケーションの親コンテキストである「ブートストラップ」コンテキストを作成することによって動作します。このコンテキストは、外部ソースから構成プロパティをロードし、ローカルの外部構成ファイル内のプロパティを復号化するロールを果たします。2 つのコンテキストは、Spring アプリケーションの外部プロパティのソースである Environment を共有します。デフォルトでは、ブートストラッププロパティ (bootstrap.properties ではなく、ブートストラップフェーズ中に読み込まれるプロパティ) は高い優先順位で追加されるため、ローカル構成でオーバーライドすることはできません。

ブートストラップコンテキストは、メインアプリケーションコンテキストとは異なる外部構成の検索規則を使用します。application.yml (または .properties) の代わりに bootstrap.yml を使用して、ブートストラップとメインコンテキストの外部構成を適切に分離することができます。次のリストは例を示しています。

例 1: bootstrap.yml
spring:
  application:
    name: foo
  cloud:
    config:
      uri: ${SPRING_CONFIG_URI:http://localhost:8888}

アプリケーションがサーバーからのアプリケーション固有の構成を必要とする場合は、spring.application.name ( bootstrap.yml または application.yml 内) を設定することをお勧めします。プロパティ spring.application.name をアプリケーションのコンテキスト ID として使用するには、それを bootstrap.[properties | yml] に設定する必要があります。

特定のプロファイル構成を取得する場合は、bootstrap.[properties | yml] で spring.profiles.active も設定する必要があります。

spring.cloud.bootstrap.enabled=false を (たとえば、システムプロパティで) 設定すると、ブートストラッププロセスを完全に無効にすることができます。

1.2. アプリケーションコンテキスト階層

SpringApplication または SpringApplicationBuilder からアプリケーションコンテキストを構築すると、ブートストラップコンテキストがそのコンテキストの親として追加されます。子コンテキストが親からプロパティソースとプロファイルを継承するのは Spring の機能であるため、Spring Cloud Config を使用せずに同じコンテキストを構築する場合と比較して、「メイン」アプリケーションコンテキストには追加のプロパティソースが含まれます。追加のプロパティソースは次のとおりです。

  • “ブートストラップ”: ブートストラップコンテキストで PropertySourceLocators が見つかり、空ではないプロパティがある場合、オプションの CompositePropertySource が高い優先度で表示されます。例としては、Spring Cloud Config サーバーからのプロパティがあります。このプロパティソースの内容をカスタマイズする方法については、"ブートストラッププロパティソースのカスタマイズ" を参照してください。

Spring Cloud 2022.0.3 より前は、PropertySourceLocators (Spring Cloud Config 用のものを含む) は、ブートストラップコンテキストではなく、メインアプリケーションコンテキストで実行されていました。bootstrap.[properties | yaml] で spring.cloud.config.initialize-on-context-refresh=true を設定すると、ブートストラップコンテキスト中に PropertySourceLocators を強制的に実行できます。
  • "applicationConfig" : [ クラスパス: bootstrap.yml]」 (および関連ファイル (Spring プロファイルがアクティブな場合)): bootstrap.yml (または .properties) がある場合、これらのプロパティはブートストラップコンテキストの構成に使用されます。その後、親が設定されると、子コンテキストに追加されます。これらは、application.yml (または .properties) や、Spring Boot アプリケーション作成プロセスの通常の部分として子に追加されるその他のプロパティソースよりも優先順位が低くなります。これらのプロパティソースの内容をカスタマイズする方法については、"ブートストラッププロパティの場所の変更" を参照してください。

プロパティソースの順序付け規則により、「ブートストラップ」エントリが優先されます。ただし、これらには bootstrap.yml からのデータは含まれていないことに注意してください。bootstrap.yml は優先順位が非常に低いですが、デフォルトの設定に使用できます。

作成した ApplicationContext の親コンテキストを設定することによって、コンテキスト階層を継承できます。たとえば、独自のインターフェースを使用するか、SpringApplicationBuilder の便利なメソッド (parent()child()sibling()) を使用します。ブートストラップコンテキストは、自分で作成した最も古い祖先の親です。階層内のすべてのコンテキストには、値が誤って親から子孫に昇格されることを避けるために、独自の「ブートストラップ」(空の場合もある) プロパティソースがあります。構成サーバーがある場合、階層内のすべてのコンテキストは (原則として) 異なる spring.application.name を持つことができ、異なる リモートプロパティソースを持つこともできます。通常の Spring アプリケーションコンテキストの動作ルールがプロパティの解決に適用されます。子コンテキストのプロパティは、名前およびプロパティソース名によって、親のプロパティをオーバーライドします。(子に親と同じ名前のプロパティソースがある場合、親の値は子に含まれません)。

SpringApplicationBuilder を使用すると、階層全体で Environment を共有できますが、これはデフォルトではないことに注意してください。兄弟コンテキストは (特に)、親と共通の値を共有する場合でも、同じプロファイルやプロパティソースを持つ必要はありません。

1.3. ブートストラッププロパティの場所の変更

bootstrap.yml (または .properties) の場所は、たとえばシステムプロパティで spring.cloud.bootstrap.name (デフォルト: bootstrap)、spring.cloud.bootstrap.location (デフォルト: 空)、または spring.cloud.bootstrap.additional-location (デフォルト: 空) を設定することで指定できます。

これらのプロパティは、同じ名前の spring.config.* バリアントと同様に動作します。spring.cloud.bootstrap.location では、デフォルトの場所が置き換えられ、指定された場所のみが使用されます。デフォルトのリストに場所を追加するには、spring.cloud.bootstrap.additional-location を使用できます。実際、これらのプロパティは、Environment にこれらのプロパティを設定することで、ブートストラップ ApplicationContext をセットアップするために使用されます。アクティブなプロファイルがある場合 (spring.profiles.active から、または構築しているコンテキストの Environment API を通じて)、通常の Spring Boot アプリと同様に、そのプロファイル内のプロパティも読み込まれます (たとえば、development プロファイルの場合は bootstrap-development.properties から)。

1.4. リモートプロパティの値のオーバーライド

ブートストラップコンテキストによってアプリケーションに追加されるプロパティソースは、多くの場合「リモート」です (たとえば、Spring Cloud Config サーバーから)。デフォルトでは、ローカルでオーバーライドすることはできません。アプリケーションが独自のシステムプロパティまたは構成ファイルで リモートプロパティをオーバーライドできるようにする場合、リモートプロパティソースは spring.cloud.config.allowOverride=true を設定してアクセス許可を付与する必要があります (これをローカルで設定することはできません)。このフラグが設定されると、システムプロパティとアプリケーションのローカル構成に関連した リモートプロパティの場所が、2 つのより詳細な設定によって制御されます。

  • spring.cloud.config.overrideNone=true: ローカルプロパティソースからオーバーライドします。

  • spring.cloud.config.overrideSystemProperties=false: システムプロパティ、コマンドライン引数、環境変数のみ (ローカル構成ファイルは不可) が リモート 設定をオーバーライドする必要があります。

1.5. ブートストラップ構成のカスタマイズ

ブートストラップコンテキストは、org.springframework.cloud.bootstrap.BootstrapConfiguration という名前のキーの /META-INF/spring.factories にエントリを追加することで、任意の操作を行うように設定できます。これには、コンテキストの作成に使用される Spring @Configuration クラスのカンマ区切りのリストが保持されます。オートワイヤーのためにメインアプリケーションコンテキストで使用できるようにする Bean は、ここで作成できます。ApplicationContextInitializer 型の @Beans には特約がございます。起動シーケンスを制御したい場合は、クラスに @Order アノテーションをマークできます (デフォルトの順序は last)。

カスタム BootstrapConfiguration を追加するときは、追加するクラスが必要のない「メイン」アプリケーションコンテキストに誤って @ComponentScanned にならないように注意してください。Boot 構成クラスには別のパッケージ名を使用し、その名前が @ComponentScan または @SpringBootApplication アノテーション付き構成クラスですでにカバーされていないことを確認してください。

ブートストラッププロセスは、メイン SpringApplication インスタンスに初期化子を挿入して終了します (これは、スタンドアロンアプリケーションとして実行されるか、アプリケーションサーバーにデプロイされるかに関係なく、通常の Spring Boot 起動シーケンスです)。まず、spring.factories にあるクラスからブートストラップコンテキストが作成されます。次に、型 ApplicationContextInitializer のすべての @Beans が、メイン SpringApplication が開始される前にメイン SpringApplication に追加されます。

1.6. ブートストラッププロパティソースのカスタマイズ

ブートストラッププロセスによって追加される外部構成のデフォルトのプロパティソースは Spring Cloud Config サーバーですが、型 PropertySourceLocator の Bean を ( spring.factories を介して) ブートストラップコンテキストに追加することで、追加のソースを追加できます。たとえば、別のサーバーまたはデータベースから追加のプロパティを挿入できます。

例として、次のカスタムロケーターを考えてみましょう。

@Configuration
public class CustomPropertySourceLocator implements PropertySourceLocator {

    @Override
    public PropertySource<?> locate(Environment environment) {
        return new MapPropertySource("customProperty",
                Collections.<String, Object>singletonMap("property.from.sample.custom.source", "worked as intended"));
    }

}

渡される Environment は、これから作成される ApplicationContext 用の Environment です。つまり、追加のプロパティソースを提供する Environment です。通常の Spring Boot が提供するプロパティソースがすでに存在するため、使用して、この Environment に固有のプロパティソースを見つけることができます (たとえば、デフォルトの Spring Cloud Config サーバープロパティソースロケーターで行われるように、spring.application.name にキーを入力することによって)。

このクラスを含む jar を作成し、次の設定を含む META-INF/spring.factories を追加すると、その jar をクラスパスに含むアプリケーションに customPropertyPropertySource が表示されます。

org.springframework.cloud.bootstrap.BootstrapConfiguration=sample.custom.CustomPropertySourceLocator

Spring Cloud 2022.0.3 以降、Spring Cloud は PropertySourceLocators を 2 回呼び出すようになります。最初のフェッチでは、プロファイルを含まないプロパティソースが取得されます。これらのプロパティソースには、spring.profiles.active を使用してプロファイルをアクティブ化する機会があります。メインアプリケーションコンテキストが開始された後、PropertySourceLocators が 2 回目に呼び出されます。このときはアクティブなプロファイルが使用され、PropertySourceLocators はプロファイルを持つ追加の PropertySources を見つけることができます。

1.7. ロギング構成

Spring Boot を使用してログ設定を構成する場合、すべてのイベントに適用したい場合は、この構成を bootstrap.[yml | properties] に配置する必要があります。

Spring Cloud がログ構成を適切に初期化するには、カスタムプレフィックスを使用することはできません。例: custom.loggin.logpath の使用は、ロギングシステムの初期化時に Spring Cloud によって認識されません。

1.8. 環境の変化

アプリケーションは EnvironmentChangeEvent をリッスンし、いくつかの標準的な方法で変更に反応します (追加の ApplicationListeners は通常の方法で @Beans として追加できます)。EnvironmentChangeEvent が観察されると、変更されたキー値のリストがあり、アプリケーションはそれらを使用して次のことを行います。

  • コンテキスト内の @ConfigurationProperties Bean を再バインドします。

  • logging.level.* のプロパティのロガーレベルを設定します。

Spring Cloud Config クライアントは、デフォルトでは Environment の変更をポーリングしないことに注意してください。一般に、変更を検出するためにそのアプローチはお勧めしません (ただし、@Scheduled アノテーションを使用してセットアップすることはできます)。スケールアウトされたクライアントアプリケーションがある場合は、(たとえば、Spring Cloud Bus [GitHub] (英語) を使用して) 変更をポーリングさせる代わりに、すべてのインスタンスに EnvironmentChangeEvent をブロードキャストすることをお勧めします。

EnvironmentChangeEvent は、実際に Environment に変更を加えてイベントを発行できる限り、大規模なクラスのリフレッシュユースケースをカバーします。これらの API はパブリックであり、コア Spring の一部であることに注意してください。/configprops エンドポイント (標準の Spring Boot Actuator 機能) にアクセスすると、変更が @ConfigurationProperties Bean にバインドされていることを確認できます。たとえば、DataSource は実行時に maxPoolSize を変更し (Spring Boot によって作成されるデフォルトの DataSource は @ConfigurationProperties Bean です)、容量を動的に拡張できます。@ConfigurationProperties の再バインドは、リフレッシュをより詳細に制御する必要がある場合や、ApplicationContext 全体に対してアトミックな変更が必要な場合など、別の大きなクラスのユースケースには対応していません。これらの関心事に対処するために、@RefreshScope があります。

1.9. リフレッシュスコープ

構成の変更がある場合、@RefreshScope としてマークされている Spring @Bean は特別な扱いを受けます。この機能は、初期化時にのみ構成が挿入されるステートフル Bean の問題に対処します。たとえば、データベース URL が Environment を通じて変更されたときに DataSource が開いている接続がある場合、おそらく、それらの接続の所有者が実行中の作業を完了できるようにする必要があります。その後、次回何かがプールから接続を借用するときに、新しい URL を持つ接続を取得します。

場合によっては、一度しか初期化できない一部の Bean に @RefreshScope アノテーションを適用することが必須になる場合もあります。Bean が「不変」の場合、Bean に @RefreshScope のアノテーションを付けるか、プロパティキー spring.cloud.refresh.extra-refreshable にクラス名を指定する必要があります。

DataSource Bean が HikariDataSource である場合は、リフレッシュできません。これは spring.cloud.refresh.never-refreshable のデフォルト値です。リフレッシュする必要がある場合は、別の DataSource 実装を選択してください。

リフレッシュスコープ Bean は、使用時 (つまり、メソッドの呼び出し時) に初期化される遅延プロキシであり、スコープは初期化された値のキャッシュとして機能します。次のメソッド呼び出しで Bean を強制的に再初期化するには、そのキャッシュエントリを無効にする必要があります。

RefreshScope はコンテキスト内では Bean であり、ターゲットキャッシュをクリアすることでスコープ内のすべての Bean をリフレッシュするパブリック refreshAll() メソッドを備えています。/refresh エンドポイントは、この機能を (HTTP または JMX 経由で) 公開します。個々の Bean を名前でリフレッシュするには、refresh(String) メソッドもあります。

/refresh エンドポイントを公開するには、次の構成をアプリケーションに追加する必要があります。

management:
  endpoints:
    web:
      exposure:
        include: refresh
@RefreshScope は (技術的には) @Configuration クラスで動作しますが、予期しない動作が発生する可能性があります。例: そのクラスで定義されているすべての @Beans 自体が @RefreshScope にあるという意味ではありません。具体的には、これらの Bean に依存するものは、それ自体が @RefreshScope 内にない限り、リフレッシュの開始時にリフレッシュされることに依存できません。その場合、リフレッシュ時に再構築され、その依存関係が再注入されます。その時点で、それらはリフレッシュされた @Configuration から再初期化されます)。
構成値を削除してからリフレッシュを実行しても、構成値の存在はリフレッシュされません。リフレッシュ後に値をリフレッシュするには、構成プロパティが存在する必要があります。アプリケーション内の値の存在に依存している場合は、代わりに値の不在に依存するようにロジックを切り替えることができます。もう 1 つのオプションは、アプリケーションの構成に値が存在しないのではなく、値の変化に依存することです。
コンテキストのリフレッシュは、Spring AOT 変換およびネイティブイメージではサポートされていません。AOT およびネイティブイメージの場合、spring.cloud.refresh.enabled を false に設定する必要があります。

1.10. 暗号化と復号化

Spring Cloud には、プロパティ値をローカルで復号化するための Environment プリプロセッサーがあります。Spring Cloud Config サーバーと同じルールに従い、encrypt.* を介した同じ外部構成を持ちます。暗号化された値を {cipher}* の形式で使用でき、有効なキーがある限り、メインアプリケーションコンテキストが Environment 設定を取得する前に値が復号化されます。アプリケーションで暗号化機能を使用するには、クラスパス (Maven 座標: org.springframework.security:spring-security-rsa) に Spring Security RSA を含める必要があります。また、JVM には完全な強度の JCE 拡張機能も必要です。

「不正なキーサイズ」による例外が発生し、Sun の JDK を使用している場合は、Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction ポリシーファイルをインストールする必要があります。詳細については、次のリンクを参照してください。

使用する JRE/JDK x64/x86 のバージョンに応じて、ファイルを JDK/jre/lib/security フォルダーに抽出します。

1.11. エンドポイント

Spring Boot Actuator アプリケーションの場合、追加の管理エンドポイントがいくつか利用可能です。次のものが使用できます。

  • POST を /actuator/env に変更して、Environment を更新し、@ConfigurationProperties とログレベルを再バインドします。このエンドポイントを有効にするには、management.endpoint.env.post.enabled=true を設定する必要があります。

  • /actuator/refresh を使用して Boot ストラップコンテキストを再ロードし、@RefreshScope Bean をリフレッシュします。

  • /actuator/restart を使用して ApplicationContext を閉じ、再起動します (デフォルトでは無効)。

  •  Lifecycle メソッド ( ApplicationContextstop() および start() ) を呼び出すための /actuator/pause および /actuator/resume

/actuator/env エンドポイントに対して POST メソッドを有効にすると、アプリケーション環境変数の管理に柔軟性と利便性が提供されますが、潜在的なセキュリティリスクを防ぐために、エンドポイントがセキュリティで保護され、監視されていることを確認することが重要です。spring-boot-starter-security 依存関係を追加して、アクチュエーターのエンドポイントのアクセス制御を構成します。
/actuator/restart エンドポイントを無効にすると、/actuator/pause および /actuator/resume エンドポイントも無効になります。これは、これらは /actuator/restart の特殊なケースにすぎないためです。

2. Spring Cloud Commons: 一般的な抽象化

サービスディスカバリ、ロードバランシング、サーキットブレーカーなどのパターンは、実装 (たとえば、Eureka または Consul によるディスカバリ) に関係なく、すべての Spring Cloud クライアントによって使用できる共通の抽象化レイヤーに役立ちます。

2.1. @EnableDiscoveryClient アノテーション

Spring Cloud Commons は @EnableDiscoveryClient アノテーションを提供します。これは、META-INF/spring.factories を使用した DiscoveryClient および ReactiveDiscoveryClient インターフェースの実装を探します。検出クライアントの実装では、org.springframework.cloud.client.discovery.EnableDiscoveryClient キーの spring.factories に構成クラスを追加します。DiscoveryClient 実装の例には、Spring Cloud Netflix Eureka (英語) Spring Cloud Consul ディスカバリ (英語) Spring Cloud Zookeeper ディスカバリ (英語) があります。

Spring Cloud は、デフォルトでブロッキングサービスディスカバリクライアントとリアクティブサービスディスカバリクライアントの両方を提供します。spring.cloud.discovery.blocking.enabled=false または spring.cloud.discovery.reactive.enabled=false を設定することで、ブロッキングクライアントやリアクティブクライアントを簡単に無効にすることができます。サービス検出を完全に無効にするには、spring.cloud.discovery.enabled=false を設定するだけです。

デフォルトでは、DiscoveryClient の実装はローカル Spring Boot サーバーを リモート 検出サーバーに自動登録します。この動作は、@EnableDiscoveryClient で autoRegister=false を設定することで無効にできます。

@EnableDiscoveryClient は不要になりました。クラスパスに DiscoveryClient 実装を配置して、Spring Boot アプリケーションをサービス検出サーバーに登録させることができます。

2.1.1. ヘルスインジケーター

Commons は、次の Spring Boot ヘルスインジケーターを自動構成します。

DiscoveryClientHealthIndicator

この正常性インジケーターは、現在登録されている DiscoveryClient 実装に基づいています。

  • 完全に無効にするには、spring.cloud.discovery.client.health-indicator.enabled=false を設定します。

  • 説明フィールドを無効にするには、spring.cloud.discovery.client.health-indicator.include-description=false を設定します。そうしないと、ロールアップされた HealthIndicator の description としてバブルアップする可能性があります。

  • サービスの取得を無効にするには、spring.cloud.discovery.client.health-indicator.use-services-query=false を設定します。デフォルトでは、インジケーターはクライアントの getServices メソッドを呼び出します。多くのサービスが登録されている デプロイ では、チェックのたびにすべてのサービスを取得するにはコストがかかりすぎる可能性があります。これにより、サービスの取得がスキップされ、代わりにクライアントの probe メソッドが使用されます。

DiscoveryCompositeHealthContributor

この複合ヘルスインジケーターは、登録されているすべての DiscoveryHealthIndicator Bean に基づいています。無効にするには、spring.cloud.discovery.client.composite-indicator.enabled=false を設定します。

2.1.2. DiscoveryClient インスタンスのオーダー

DiscoveryClient インターフェースは Ordered を継承します。これは、Spring アプリケーションによってロードされた Bean を順序付ける方法と同様に、返される検出クライアントの順序を定義できるため、複数の検出クライアントを使用する場合に便利です。デフォルトでは、DiscoveryClient の順序は 0 に設定されます。カスタム DiscoveryClient 実装に別の順序を設定したい場合は、セットアップに適した値を返すように getOrder() メソッドをオーバーライドするだけです。これとは別に、プロパティを使用して、ConsulDiscoveryClientEurekaDiscoveryClientZookeeperDiscoveryClient などの Spring Cloud によって提供される DiscoveryClient 実装の順序を設定できます。これを行うには、spring.cloud.{clientIdentifier}.discovery.order (Eureka の場合は eureka.client.order ) プロパティを目的の値に設定するだけです。

2.1.3. SimpleDiscoveryClient

クラスパスに Service-Registry に基づく DiscoveryClient がない場合は、プロパティを使用してサービスとインスタンスに関する情報を取得する SimpleDiscoveryClient インスタンスが使用されます。

利用可能なインスタンスに関する情報は、プロパティを介して次の形式で渡される必要があります: spring.cloud.discovery.client.simple.instances.service1[0].uri=http://s11:8080、ここで spring.cloud.discovery.client.simple.instances は共通のプレフィックス、service1 は問題のサービスの ID を表し、[0] はインスタンスのインデックス番号を示します (表示されているように) この例では、インデックスは 0 で始まり、uri の値がインスタンスを使用できる実際の URI になります。

2.2. ServiceRegistry

Commons は、カスタム登録サービスを提供できる register(Registration) や deregister(Registration) などのメソッドを提供する ServiceRegistry インターフェースを提供するようになりました。Registration はマーカーインターフェースです。

次の例は、ServiceRegistry の使用例を示しています。

@Configuration
@EnableDiscoveryClient(autoRegister=false)
public class MyConfiguration {
    private ServiceRegistry registry;

    public MyConfiguration(ServiceRegistry registry) {
        this.registry = registry;
    }

    // called through some external process, such as an event or a custom actuator endpoint
    public void register() {
        Registration registration = constructRegistration();
        this.registry.register(registration);
    }
}

各 ServiceRegistry 実装には独自の Registry 実装があります。

  • ZookeeperRegistration は ZookeeperServiceRegistry と一緒に使用されます

  • EurekaRegistration は EurekaServiceRegistry と一緒に使用されます

  • ConsulRegistration は ConsulServiceRegistry と一緒に使用されます

ServiceRegistry インターフェースを使用している場合は、使用している ServiceRegistry 実装に正しい Registry 実装を渡す必要があります。

2.2.1. ServiceRegistry 自動登録

デフォルトでは、ServiceRegistry 実装は実行中のサービスを自動登録します。この動作を無効にするには、次のように設定します。* @EnableDiscoveryClient(autoRegister=false) を設定して自動登録を永続的に無効にします。* spring.cloud.service-registry.auto-registration.enabled=false は設定を通じて動作を無効にします。

ServiceRegistry 自動登録イベント

サービスが自動登録されるときに発生するイベントが 2 つあります。InstancePreRegisteredEvent と呼ばれる最初のイベントは、サービスが登録される前に発生します。2 番目のイベントは InstanceRegisteredEvent と呼ばれ、サービスが登録された後に発生します。ApplicationListener を登録して、これらのイベントをリッスンして反応することができます。

spring.cloud.service-registry.auto-registration.enabled プロパティが false に設定されている場合、これらのイベントは発生しません。

2.2.2. サービスレジストリアクチュエーターエンドポイント

Spring Cloud Commons は、/serviceregistry アクチュエーターエンドポイントを提供します。このエンドポイントは、Spring アプリケーションコンテキストの Registration Bean に依存します。GET を使用して /serviceregistry を呼び出すと、Registration のステータスが返されます。JSON 本文を使用して同じエンドポイントに POST を使用すると、現在の Registration のステータスが新しい値に変更されます。JSON 本文には、優先値を含む status フィールドを含める必要があります。ステータスを更新するときに使用できる値と、ステータスに対して返される値については、使用する ServiceRegistry 実装のドキュメントを参照してください。たとえば、Eureka でサポートされるステータスは UPDOWNOUT_OF_SERVICEUNKNOWN です。

2.3. ロードバランサクライアントとしての Spring RestTemplate

ロードバランサークライアントを使用するように RestTemplate を構成できます。負荷分散された RestTemplate を作成するには、次の例に示すように、RestTemplate@Bean を作成し、@LoadBalanced 修飾子を使用します。

@Configuration
public class MyConfiguration {

    @LoadBalanced
    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

public class MyClass {
    @Autowired
    private RestTemplate restTemplate;

    public String doOtherStuff() {
        String results = restTemplate.getForObject("http://stores/stores", String.class);
        return results;
    }
}
RestTemplate Bean は自動構成によって作成されなくなりました。個々のアプリケーションがそれを作成する必要があります。

URI では仮想ホスト名 (つまり、ホスト名ではなくサービス名) を使用する必要があります。BlockingLoadBalancerClient は完全な物理アドレスを作成するために使用されます。

負荷分散された RestTemplate を使用するには、クラスパスにロードバランサーの実装が必要です。Spring Cloud LoadBalancer スターターを使用するには、プロジェクトに追加します。

2.4. ロードバランサクライアントとしての Spring WebClient

ロードバランサークライアントを自動的に使用するように WebClient を構成できます。負荷分散された WebClient を作成するには、次のように WebClient.Builder@Bean を作成し、@LoadBalanced 修飾子を使用します。

@Configuration
public class MyConfiguration {

    @Bean
    @LoadBalanced
    public WebClient.Builder loadBalancedWebClientBuilder() {
        return WebClient.builder();
    }
}

public class MyClass {
    @Autowired
    private WebClient.Builder webClientBuilder;

    public Mono<String> doOtherStuff() {
        return webClientBuilder.build().get().uri("http://stores/stores")
                        .retrieve().bodyToMono(String.class);
    }
}

URI では仮想ホスト名 (つまり、ホスト名ではなくサービス名) を使用する必要があります。Spring Cloud LoadBalancer は、完全な物理アドレスを作成するために使用されます。

@LoadBalanced WebClient.Builder を使用する場合は、クラスパスにロードバランサーを実装する必要があります。Spring Cloud LoadBalancer スターターをプロジェクトに追加することをお勧めします。そしてそに ReactiveLoadBalancer を使用します。

2.4.1. 失敗したリクエストの再試行

負荷分散された RestTemplate は、失敗したリクエストを再試行するように構成できます。デフォルトでは、このロジックは無効になっています。非リアクティブバージョン ( RestTemplate を使用) の場合は、アプリケーションのクラスパスに Spring Retry [GitHub] (英語) を追加することで有効にできます。リアクティブバージョン ( WebTestClient を使用) の場合は、spring.cloud.loadbalancer.retry.enabled=true を設定する必要があります。

クラスパス上で Spring Retry または Reactive Retry による再試行ロジックを無効にしたい場合は、spring.cloud.loadbalancer.retry.enabled=false を設定できます。

非リアクティブ実装の場合、再試行で BackOffPolicy を実装したい場合は、LoadBalancedRetryFactory 型の Bean を作成し、createBackOffPolicy() メソッドをオーバーライドする必要があります。

リアクティブ実装の場合は、spring.cloud.loadbalancer.retry.backoff.enabled を false に設定して有効にするだけです。

以下を設定できます。

  • spring.cloud.loadbalancer.retry.maxRetriesOnSameServiceInstance - 同じ ServiceInstance 上でリクエストを何回再試行するかを示します (選択したインスタンスごとに個別にカウントされます)

  • spring.cloud.loadbalancer.retry.maxRetriesOnNextServiceInstance - 新しく選択された ServiceInstance がリクエストを再試行する回数を示します

  • spring.cloud.loadbalancer.retry.retryableStatusCodes - 失敗したリクエストを常に再試行するためのステータスコード。

リアクティブ実装では、さらに以下を設定できます。- spring.cloud.loadbalancer.retry.backoff.minBackoff - 最小バックオフ期間を設定します (デフォルトでは、5 ミリ秒) - spring.cloud.loadbalancer.retry.backoff.maxBackoff - 最大バックオフ期間を設定します (デフォルトでは、ミリ秒の最大長値) - spring.cloud.loadbalancer.retry.backoff.jitter - 使用されるジッタを設定します。各コールの実際のバックオフ期間を計算します (デフォルトでは 0.5)。

リアクティブ実装の場合は、独自の LoadBalancerRetryPolicy を実装して、負荷分散された呼び出しの再試行をより詳細に制御することもできます。

どちらの実装でも、spring.cloud.loadbalancer.[serviceId].retry.retryable-exceptions プロパティに値のリストを追加することで、応答をトリガーする例外を設定することもできます。そうする場合、再試行可能なステータスコードも再試行できるように、提供した例外のリストに RetryableStatusCodeExceptions を必ず追加します。プロパティで例外を指定しない場合、デフォルトで使用される例外は IOExceptionTimeoutExceptionRetryableStatusCodeException です。spring.cloud.loadbalancer.[serviceId].retry.retry-on-all-exceptions を true に設定することで、すべての例外での再試行を有効にすることもできます。

Spring 再試行でブロッキング実装を使用する場合、以前のリリースの動作を保持したい場合は、ブロッキング実装のデフォルトモードとして使用されていた spring.cloud.loadbalancer.[serviceId].retry.retry-on-all-exceptions を true に設定します。
個々のロードバランサークライアントは、プレフィックスが spring.cloud.loadbalancer.clients.<clientId>.* (clientId がロードバランサーの名前) であることを除き、上記と同じプロパティを使用して個別に構成できます。
負荷分散された再試行の場合、デフォルトでは、ServiceInstanceListSupplier Bean を RetryAwareServiceInstanceListSupplier でラップして、以前に選択したインスタンスとは異なるインスタンスを選択します (可能な場合)。この動作を無効にするには、spring.cloud.loadbalancer.retry.avoidPreviousInstance の値を false に設定します。
@Configuration
public class MyConfiguration {
    @Bean
    LoadBalancedRetryFactory retryFactory() {
        return new LoadBalancedRetryFactory() {
            @Override
            public BackOffPolicy createBackOffPolicy(String service) {
                return new ExponentialBackOffPolicy();
            }
        };
    }
}

再試行機能に 1 つ以上の RetryListener 実装を追加する場合は、次の例に示すように、型 LoadBalancedRetryListenerFactory の Bean を作成し、特定のサービスに使用する RetryListener 配列を返す必要があります。

@Configuration
public class MyConfiguration {
    @Bean
    LoadBalancedRetryListenerFactory retryListenerFactory() {
        return new LoadBalancedRetryListenerFactory() {
            @Override
            public RetryListener[] createRetryListeners(String service) {
                return new RetryListener[]{new RetryListener() {
                    @Override
                    public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
                        //TODO Do you business...
                        return true;
                    }

                    @Override
                     public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
                        //TODO Do you business...
                    }

                    @Override
                    public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
                        //TODO Do you business...
                    }
                }};
            }
        };
    }
}

2.5. 複数の RestTemplate オブジェクト

負荷分散されていない RestTemplate が必要な場合は、RestTemplate Bean を作成して挿入します。負荷分散された RestTemplate にアクセスするには、次の例に示すように、@Bean の作成時に @LoadBalanced 修飾子を使用します。

@Configuration
public class MyConfiguration {

    @LoadBalanced
    @Bean
    RestTemplate loadBalanced() {
        return new RestTemplate();
    }

    @Primary
    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

public class MyClass {
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    @LoadBalanced
    private RestTemplate loadBalanced;

    public String doOtherStuff() {
        return loadBalanced.getForObject("http://stores/stores", String.class);
    }

    public String doStuff() {
        return restTemplate.getForObject("http://example.com", String.class);
    }
}
前の例では、修飾されていない @Autowired インジェクションを明確にするために、プレーンな RestTemplate 宣言で @Primary アノテーションが使用されていることに注意してください。
java.lang.IllegalArgumentException: Can not set org.springframework.web.client.RestTemplate field com.my.app.Foo.restTemplate to com.sun.proxy.$Proxy89 などのエラーが表示された場合は、RestOperations を挿入するか、spring.aop.proxyTargetClass=true を設定してみてください。

2.6. 複数の WebClient オブジェクト

負荷分散されていない WebClient が必要な場合は、WebClient Bean を作成して挿入します。負荷分散された WebClient にアクセスするには、次の例に示すように、@Bean の作成時に @LoadBalanced 修飾子を使用します。

@Configuration
public class MyConfiguration {

    @LoadBalanced
    @Bean
    WebClient.Builder loadBalanced() {
        return WebClient.builder();
    }

    @Primary
    @Bean
    WebClient.Builder webClient() {
        return WebClient.builder();
    }
}

public class MyClass {
    @Autowired
    private WebClient.Builder webClientBuilder;

    @Autowired
    @LoadBalanced
    private WebClient.Builder loadBalanced;

    public Mono<String> doOtherStuff() {
        return loadBalanced.build().get().uri("http://stores/stores")
                        .retrieve().bodyToMono(String.class);
    }

    public Mono<String> doStuff() {
        return webClientBuilder.build().get().uri("http://example.com")
                        .retrieve().bodyToMono(String.class);
    }
}

2.7. ロードバランサクライアントとしての Spring WebFlux WebClient 

Spring WebFlux は、以下のトピックに従って、リアクティブ構成と非リアクティブ WebClient 構成の両方で動作できます。

2.7.1. Spring WebFlux WebClient  ReactorLoadBalancerExchangeFilterFunction 付き

ReactiveLoadBalancer を使用するように WebClient を構成できます。Spring Cloud LoadBalancer スターターをプロジェクトに追加し、spring-webflux がクラスパス上にある場合、ReactorLoadBalancerExchangeFilterFunction は自動構成されます。次の例は、リアクティブロードバランサを使用するように WebClient を設定する方法を示しています。

public class MyClass {
    @Autowired
    private ReactorLoadBalancerExchangeFilterFunction lbFunction;

    public Mono<String> doOtherStuff() {
        return WebClient.builder().baseUrl("http://stores")
            .filter(lbFunction)
            .build()
            .get()
            .uri("/stores")
            .retrieve()
            .bodyToMono(String.class);
    }
}

URI では仮想ホスト名 (つまり、ホスト名ではなくサービス名) を使用する必要があります。ReactorLoadBalancer は、完全な物理アドレスを作成するために使用されます。

2.7.2. ノンリアクティブロードバランサクライアントを備えた Spring WebFlux WebClient 

spring-webflux がクラスパス上にある場合、LoadBalancerExchangeFilterFunction は自動構成されます。ただし、これは内部で非リアクティブクライアントを使用することに注意してください。次の例は、ロードバランサを使用するように WebClient を設定する方法を示しています。

public class MyClass {
    @Autowired
    private LoadBalancerExchangeFilterFunction lbFunction;

    public Mono<String> doOtherStuff() {
        return WebClient.builder().baseUrl("http://stores")
            .filter(lbFunction)
            .build()
            .get()
            .uri("/stores")
            .retrieve()
            .bodyToMono(String.class);
    }
}

URI では仮想ホスト名 (つまり、ホスト名ではなくサービス名) を使用する必要があります。LoadBalancerClient は、完全な物理アドレスを作成するために使用されます。

WARN: このアプローチは現在非推奨です。代わりにリアクティブロードバランサを備えた WebFlux を使用することをお勧めします。

2.8. ネットワークインターフェースを無視する

場合によっては、特定の名前付きネットワークインターフェースを無視して、サービスディスカバリの登録から除外できると便利です (たとえば、Docker コンテナーで実行している場合)。正規表現のリストを設定して、目的のネットワークインターフェースを無視することができます。次の設定では、docker0 インターフェースと veth で始まるすべてのインターフェースが無視されます。

例 2: application.yml
spring:
  cloud:
    inetutils:
      ignoredInterfaces:
        - docker0
        - veth.*

次の例に示すように、正規表現のリストを使用して、指定したネットワークアドレスのみを強制的に使用することもできます。

例 3: bootstrap.yml
spring:
  cloud:
    inetutils:
      preferredNetworks:
        - 192.168
        - 10.0

次の例に示すように、サイトローカルアドレスのみの使用を強制することもできます。

例 4: application.yml
spring:
  cloud:
    inetutils:
      useOnlySiteLocalInterfaces: true

サイトローカルアドレスの構成要素の詳細については、"Inet4Address.html.isSiteLocalAddress() (標準 Javadoc) " を参照してください。

2.9. HTTP クライアントファクトリ

Spring Cloud Commons は、Apache HTTP クライアント (ApacheHttpClientFactory) と OK HTTP クライアント (OkHttpClientFactory) の両方を作成するための Bean を提供します。OkHttpClientFactory Bean は、OK HTTP jar がクラスパスにある場合にのみ作成されます。さらに、Spring Cloud Commons は、両方のクライアントで使用される接続マネージャーを作成するための Bean を提供します。Apache HTTP クライアントの場合は ApacheHttpClientConnectionManagerFactory、OK HTTP クライアントの場合は OkHttpClientConnectionPoolFactory です。下流プロジェクトで HTTP クライアントを作成する方法をカスタマイズする場合は、これらの Bean の独自の実装を提供できます。さらに、型 HttpClientBuilder または OkHttpClient.Builder の Bean を提供する場合、デフォルトのファクトリは、下流プロジェクトに返されるビルダーのベースとしてこれらのビルダーを使用します。spring.cloud.httpclientfactories.apache.enabled または spring.cloud.httpclientfactories.ok.enabled を false に設定して、これらの Bean の作成を無効にすることもできます。

2.10. 有効な機能

Spring Cloud Commons は、/features アクチュエーターエンドポイントを提供します。このエンドポイントは、クラスパスで利用可能な機能と、それらが有効かどうかを返します。返される情報には、機能の型、名前、バージョン、ベンダーが含まれます。

2.10.1. 特徴の種類

「機能」には、抽象機能と名前付き機能の 2 種類があります。

抽象機能は、インターフェースまたは抽象クラスが定義され、実装によって作成される機能です ( DiscoveryClientLoadBalancerClientLockService など)。抽象クラスまたはインターフェースは、コンテキスト内でその型の Bean を見つけるために使用されます。表示されるバージョンは bean.getClass().getPackage().getImplementationVersion() です。

名前付き機能は、実装する特定のクラスを持たない機能です。これらの機能には、「サーキットブレーカー」、「API ゲートウェイ」、"Spring Cloud Bus" などが含まれます。これらの機能には、名前と Bean 型が必要です。

2.10.2. 機能の宣言

次の例に示すように、どのモジュールでも任意の数の HasFeature Bean を宣言できます。

@Bean
public HasFeatures commonsFeatures() {
  return HasFeatures.abstractFeatures(DiscoveryClient.class, LoadBalancerClient.class);
}

@Bean
public HasFeatures consulFeatures() {
  return HasFeatures.namedFeatures(
    new NamedFeature("Spring Cloud Bus", ConsulBusAutoConfiguration.class),
    new NamedFeature("Circuit Breaker", HystrixCommandAspect.class));
}

@Bean
HasFeatures localFeatures() {
  return HasFeatures.builder()
      .abstractFeature(Something.class)
      .namedFeature(new NamedFeature("Some Other Feature", Someother.class))
      .abstractFeature(Somethingelse.class)
      .build();
}

これらの Bean はそれぞれ、適切に保護された @Configuration に入れる必要があります。

2.11. Spring Cloud 互換性の検証

一部のユーザーが Spring Cloud アプリケーションのセットアップに問題を抱えているため、互換性検証メカニズムを追加することにしました。現在のセットアップが Spring Cloud 要件と互換性がない場合は、問題が発生したことを示すレポートとともに機能が停止します。

現時点では、Spring Boot のどのバージョンがクラスパスに追加されているかを確認しています。

レポートの例

***************************
APPLICATION FAILED TO START
***************************

Description:

Your project setup is incompatible with our requirements due to following reasons:

- Spring Boot [2.1.0.RELEASE] is not compatible with this Spring Cloud release train


Action:

Consider applying the following actions:

- Change Spring Boot version to one of the following versions [1.2.x, 1.3.x] .
You can find the latest Spring Boot versions here [https://spring.io/projects/spring-boot#learn].
If you want to learn more about the Spring Cloud Release train compatibility, you can visit this page [https://spring.io/projects/spring-cloud#overview] and check the [Release Trains] section.

この機能を無効にするには、spring.cloud.compatibility-verifier.enabled を false に設定します。互換性のある Spring Boot バージョンをオーバーライドする場合は、互換性のある Spring Boot バージョンのカンマ区切りリストを使用して spring.cloud.compatibility-verifier.compatible-boot-versions プロパティを設定するだけです。

3. Spring Cloud LoadBalancer

Spring Cloud は、独自のクライアント側ロードバランサーの抽象化と実装を提供します。負荷分散メカニズムについては、ReactiveLoadBalancer インターフェースが追加され、ラウンドロビンベースおよびランダム実装が提供されています。リアクティブから選択するインスタンスを取得するには、ServiceInstanceListSupplier が使用されます。現在、クラスパスで使用可能なディスカバリクライアントを使用してサービスディスカバリから利用可能なインスタンスを取得する、サービスディスカバリベースの ServiceInstanceListSupplier 実装をサポートしています。

spring.cloud.loadbalancer.enabled の値を false に設定することで、Spring Cloud LoadBalancer を無効にすることができます。

3.1. LoadBalancer コンテキストの積極的なロード

Spring Cloud LoadBalancer は、サービス ID ごとに個別の Spring 子コンテキストを作成します。デフォルトでは、サービス ID に対する最初のリクエストが負荷分散されるたびに、これらのコンテキストは遅延初期化されます。

これらのコンテキストを積極的にロードすることを選択できます。これを行うには、spring.cloud-loadbalancer.eager-load.clients プロパティを使用して、即時ロードを実行するサービス ID を指定します。

3.2. 負荷分散アルゴリズムの切り替え

デフォルトで使用される ReactiveLoadBalancer 実装は RoundRobinLoadBalancer です。選択したサービスまたはすべてのサービスを別の実装に切り替えるには、カスタム LoadBalancer 構成メカニズムを使用できます。

例: 次の設定を @LoadBalancerClient アノテーション経由で渡して、RandomLoadBalancer の使用に切り替えることができます。

public class CustomLoadBalancerConfiguration {

    @Bean
    ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
            LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(loadBalancerClientFactory
                .getLazyProvider(name, ServiceInstanceListSupplier.class),
                name);
    }
}
@LoadBalancerClient または @LoadBalancerClients 構成引数として渡すクラスは、@Configuration のアノテーションが付けられていないか、コンポーネントのスキャン範囲外である必要があります。

3.3. Spring Cloud LoadBalancer の統合

Spring Cloud LoadBalancer を使いやすくするために、WebClient で使用できる ReactorLoadBalancerExchangeFilterFunction と、RestTemplate で動作する BlockingLoadBalancerClient を提供します。詳細と使用例については、次のセクションで説明します。

3.4. Spring Cloud LoadBalancer キャッシング

インスタンスを選択する必要があるたびに DiscoveryClient 経由でインスタンスを取得する基本的な ServiceInstanceListSupplier 実装とは別に、2 つのキャッシュ実装が提供されています。

3.4.1. Caffeine - バックアップされた LoadBalancer キャッシュ実装

クラスパスに com.github.ben-manes.caffeine:caffeine がある場合は、Caffeine ベースの実装が使用されます。設定方法については、"LoadBalancerCacheConfiguration" セクションを参照してください。

Caffeine を使用している場合は、spring.cloud.loadbalancer.cache.caffeine.spec プロパティに独自の Caffeine 仕様 (英語) を渡すことで、LoadBalancer のデフォルトの Caffeine キャッシュ設定をオーバーライドすることもできます。

WARN: 独自の Caffeine 仕様を渡すと、ttl や capacity などの一般的な LoadBalancer キャッシュ構成フィールドを含む他の LoadBalancerCache 設定がオーバーライドされます。

3.4.2. デフォルトの LoadBalancer キャッシュ実装

クラスパスに Caffeine がない場合は、spring-cloud-starter-loadbalancer に自動的に付属する DefaultLoadBalancerCache が使用されます。設定方法については、"LoadBalancerCacheConfiguration" セクションを参照してください。

デフォルトのキャッシュの代わりに Caffeine を使用するには、クラスパスに com.github.ben-manes.caffeine:caffeine 依存関係を追加します。

3.4.3. LoadBalancer キャッシュ構成

spring.cloud.loadbalancer.cache.ttl プロパティの値として Spring Boot String から Duration へのコンバーターの構文に準拠した String を渡すことで、Duration で表される独自の ttl 値(書き込み後、エントリの有効期限が切れるまでの時間)を設定できます。また、spring.cloud.loadbalancer.cache.capacity プロパティの値を設定することで、独自の LoadBalancer キャッシュ初期容量を設定することもできます。

デフォルトの設定には、35 秒に設定された ttl が含まれており、デフォルトの initialCapacity は 256 です。

spring.cloud.loadbalancer.cache.enabled の値を false に設定することで、loadBalancer キャッシュを完全に無効にすることもできます。

基本的なキャッシュされていない実装はプロトタイピングやテストには役立ちますが、キャッシュされたバージョンよりも効率がはるかに低いため、運用環境では常にキャッシュされたバージョンを使用することをお勧めします。DiscoveryClient 実装 ( EurekaDiscoveryClient など) によってキャッシュがすでに行われている場合は、二重キャッシュを防ぐためにロードバランサーのキャッシュを無効にする必要があります。
独自の構成を作成する場合、CachingServiceInstanceListSupplier を使用する場合は、ネットワーク経由でインスタンスを取得するサプライヤー ( DiscoveryClientServiceInstanceListSupplier など) の直後の階層内で、他のフィルタリングサプライヤーの前に必ず配置してください。

3.5. 加重負荷分散

加重ロードバランシングを有効にするために、WeightedServiceInstanceListSupplier が提供されています。WeightFunction を使用して各インスタンスの重みを計算します。デフォルトでは、メタデータマップから重みを読み取って解析しようとします (キーは weight)。

メタデータマップで重みが指定されていない場合、このインスタンスの重みはデフォルトで 1 になります。

これを構成するには、spring.cloud.loadbalancer.configurations の値を weighted に設定するか、独自の ServiceInstanceListSupplier Bean を指定します。例:

public class CustomLoadBalancerConfiguration {

    @Bean
    public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
            ConfigurableApplicationContext context) {
        return ServiceInstanceListSupplier.builder()
                    .withDiscoveryClient()
                    .withWeighted()
                    .withCaching()
                    .build(context);
    }
}
WeightFunction を提供することで、重み計算ロジックをカスタマイズすることもできます。

このサンプル構成を使用すると、すべてのインスタンスにランダムな重みを持たせることができます。

public class CustomLoadBalancerConfiguration {

    @Bean
    public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
            ConfigurableApplicationContext context) {
        return ServiceInstanceListSupplier.builder()
                    .withDiscoveryClient()
                    .withWeighted(instance -> ThreadLocalRandom.current().nextInt(1, 101))
                    .withCaching()
                    .build(context);
    }
}

3.6. ゾーンベースの負荷分散

ゾーンベースの負荷分散を有効にするために、ZonePreferenceServiceInstanceListSupplier が提供されています。DiscoveryClient -specific zone 構成 (たとえば、eureka.instance.metadata-map.zone) を使用して、クライアントが利用可能なサービスインスタンスをフィルタリングしようとするゾーンを選択します。

spring.cloud.loadbalancer.zone プロパティの値を設定することで、DiscoveryClient -specific ゾーン設定をオーバーライドすることもできます。
当面は、LoadBalancer ゾーンを設定するために Eureka Discovery Client のみが装備されています。他の検出クライアントの場合は、spring.cloud.loadbalancer.zone プロパティを設定します。さらに多くの機器が間もなく登場します。
取得した ServiceInstance のゾーンを判断するには、そのメタデータマップ内の "zone" キーの値を確認します。

ZonePreferenceServiceInstanceListSupplier は、取得したインスタンスをフィルタリングし、同じゾーン内のインスタンスのみを返します。ゾーンが null である場合、または同じゾーン内にインスタンスがない場合は、取得されたすべてのインスタンスが返されます。

ゾーンベースの負荷分散アプローチを使用するには、カスタム構成で ZonePreferenceServiceInstanceListSupplier Bean をインスタンス化する必要があります。

ServiceInstanceListSupplier Bean を操作するためにデリゲートを使用します。DiscoveryClientServiceInstanceListSupplier デリゲートを使用し、それを CachingServiceInstanceListSupplier でラップして LoadBalancer キャッシュメカニズムを利用し、結果の Bean を ZonePreferenceServiceInstanceListSupplier のコンストラクターに渡すことをお勧めします。

このサンプル構成を使用してセットアップできます。

public class CustomLoadBalancerConfiguration {

    @Bean
    public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
            ConfigurableApplicationContext context) {
        return ServiceInstanceListSupplier.builder()
                    .withDiscoveryClient()
                    .withCaching()
                    .withZonePreference()
                    .build(context);
    }
}

3.7. LoadBalancer のインスタンスのヘルスチェック

LoadBalancer に対してスケジュールされた HealthCheck を有効にすることができます。HealthCheckServiceInstanceListSupplier はそのために提供されています。デリゲート ServiceInstanceListSupplier によって提供されたインスタンスがまだ生きているかどうかを定期的に確認し、正常なインスタンスのみを返します (存在しない場合は、取得したすべてのインスタンスを返します)。

このメカニズムは、SimpleDiscoveryClient を使用する場合に特に役立ちます。実際のサービスレジストリによってサポートされているクライアントの場合、外部 ServiceDiscovery にクエリを実行した後、正常なインスタンスがすでに取得されているため、サービスレジストリを使用する必要はありません。
このサプライヤーは、失敗したインスタンスでの呼び出しの再試行を避けるために、サービスあたりのインスタンス数が少ないセットアップにも推奨されます。
サービスディスカバリ がサポートするサプライヤーを使用している場合は、インスタンスの健全性状態を Service Registry から直接取得するため、通常、この健全性チェックメカニズムを追加する必要はありません。
HealthCheckServiceInstanceListSupplier は、デリゲートフラックスによって提供されるリフレッシュされたインスタンスに依存します。まれに、インスタンスのリストが変更される可能性があるにもかかわらず (当社が提供する DiscoveryClientServiceInstanceListSupplier など)、インスタンスをリフレッシュしないデリゲートを使用したい場合は、spring.cloud.loadbalancer.health-check.refetch-instances を true に設定して、HealthCheckServiceInstanceListSupplier。また、spring.cloud.loadbalancer.health-check.refetch-instances-interval の値を変更して再取得間隔を調整したり、インスタンスの再取得ごとにヘルスチェックもトリガーされるため、spring.cloud.loadbalancer.health-check.repeat-health-check を false に設定して追加のヘルスチェックの繰り返しを無効にすることもできます。

HealthCheckServiceInstanceListSupplier は、spring.cloud.loadbalancer.health-check という接頭辞が付いているプロパティを使用します。スケジューラーには initialDelay と interval を設定できます。spring.cloud.loadbalancer.health-check.path.default プロパティの値を設定することで、ヘルスチェック URL のデフォルトのパスを設定できます。spring.cloud.loadbalancer.health-check.path.[SERVICE_ID] プロパティの値を設定し、[SERVICE_ID] をサービスの正しい ID に置き換えることにより、特定のサービスに特定の値を設定することもできます。[SERVICE_ID] が指定されていない場合は、デフォルトで /actuator/health が使用されます。[SERVICE_ID] が null に設定されている場合、または値が空の場合、ヘルスチェックは実行されません。spring.cloud.loadbalancer.health-check.port の値を設定することで、ヘルスチェックリクエスト用のカスタムポートを設定することもできます。何も設定されていない場合、リクエストされたサービスをサービスインスタンスで使用できるポート。

デフォルトのパス (/actuator/health) に依存する場合は、そのようなエンドポイントを独自に追加する予定がない限り、必ず spring-boot-starter-actuator をコラボレーターの依存関係に追加してください。
デフォルトでは、healthCheckFlux は、取得された生きている ServiceInstance ごとに出力します。この動作を変更するには、spring.cloud.loadbalancer.health-check.update-results-list の値を false に設定します。このプロパティが false に設定されている場合、生きているインスタンスのシーケンス全体が最初にリストに収集され、その後にのみ出力されます。これにより、フラックスがプロパティで設定されたヘルスチェック間隔の間に値を出力しないことが保証されます。

ヘルスチェックスケジューラのアプローチを使用するには、カスタム構成で HealthCheckServiceInstanceListSupplier Bean をインスタンス化する必要があります。

ServiceInstanceListSupplier Bean を操作するためにデリゲートを使用します。HealthCheckServiceInstanceListSupplier のコンストラクターで DiscoveryClientServiceInstanceListSupplier デリゲートを渡すことをお勧めします。

このサンプル構成を使用してセットアップできます。

public class CustomLoadBalancerConfiguration {

    @Bean
    public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
            ConfigurableApplicationContext context) {
        return ServiceInstanceListSupplier.builder()
                    .withDiscoveryClient()
                    .withHealthChecks()
                    .build(context);
        }
    }
非リアクティブスタックの場合は、withBlockingHealthChecks() を使用してこのサプライヤーを作成します。チェックに使用する独自の WebClient または RestTemplate インスタンスを渡すこともできます。
HealthCheckServiceInstanceListSupplier には、Reactor Flux replay() に基づく独自のキャッシュメカニズムがあります。それが使用されている場合は、そのサプライヤーを CachingServiceInstanceListSupplier でラップするのをスキップすることをお勧めします。
独自の構成 HealthCheckServiceInstanceListSupplier を作成する場合は、ネットワーク経由でインスタンスを取得するサプライヤー ( DiscoveryClientServiceInstanceListSupplier など) の直後の階層内で、他のフィルタリングサプライヤーの前に必ず配置してください。

3.8. LoadBalancer の同じインスタンス設定

以前に選択されたインスタンスが使用可能な場合、そのインスタンスが優先されるように LoadBalancer をセットアップできます。

そのためには、SameInstancePreferenceServiceInstanceListSupplier を使用する必要があります。これを構成するには、spring.cloud.loadbalancer.configurations の値を same-instance-preference に設定するか、独自の ServiceInstanceListSupplier Bean を指定します。たとえば、次のようになります。

public class CustomLoadBalancerConfiguration {

    @Bean
    public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
            ConfigurableApplicationContext context) {
        return ServiceInstanceListSupplier.builder()
                    .withDiscoveryClient()
                    .withSameInstancePreference()
                    .build(context);
        }
    }
これも Zookeeper StickyRule の代替です。

3.9. LoadBalancer のリクエストベースのスティッキーセッション

リクエスト Cookie で提供される instanceId を持つインスタンスが優先されるように LoadBalancer をセットアップできます。現在、リクエストが ClientRequestContext または ServerHttpRequestContext を介して LoadBalancer に渡される場合、これはサポートされています。これらは SC LoadBalancer 交換フィルター関数およびフィルターによって使用されます。

そのためには、RequestBasedStickySessionServiceInstanceListSupplier を使用する必要があります。これを構成するには、spring.cloud.loadbalancer.configurations の値を request-based-sticky-session に設定するか、独自の ServiceInstanceListSupplier Bean を指定します。たとえば、次のようになります。

public class CustomLoadBalancerConfiguration {

    @Bean
    public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
            ConfigurableApplicationContext context) {
        return ServiceInstanceListSupplier.builder()
                    .withDiscoveryClient()
                    .withRequestBasedStickySession()
                    .build(context);
        }
    }

この機能では、リクエストを転送する前に、選択したサービスインスタンス (元のリクエスト Cookie が使用できない場合は、そのサービスインスタンスと異なる可能性があります) を更新できると便利です。これを行うには、spring.cloud.loadbalancer.sticky-session.add-service-instance-cookie の値を true に設定します。

デフォルトでは、Cookie の名前は sc-lb-instance-id です。spring.cloud.loadbalancer.instance-id-cookie-name プロパティの値を変更することで変更できます。

この機能は現在、WebClient ベースのロードバランシングでサポートされています。

3.10. Spring Cloud LoadBalancer ヒント

Spring Cloud LoadBalancer を使用すると、Request オブジェクト内の LoadBalancer に渡され、後で処理できる ReactiveLoadBalancer 実装で使用できる String ヒントを設定できます。

spring.cloud.loadbalancer.hint.default プロパティの値を設定することで、すべてのサービスのデフォルトのヒントを設定できます。spring.cloud.loadbalancer.hint.[SERVICE_ID] プロパティの値を設定し、[SERVICE_ID] をサービスの正しい ID に置き換えることにより、特定のサービスに特定の値を設定することもできます。ユーザーがヒントを設定しない場合は、default が使用されます。

3.11. ヒントベースの負荷分散

また、ヒントベースのインスタンス選択のための ServiceInstanceListSupplier 実装である HintBasedServiceInstanceListSupplier も提供します。

HintBasedServiceInstanceListSupplier は、ヒントリクエストヘッダー (デフォルトのヘッダー名は X-SC-LB-Hint ですが、spring.cloud.loadbalancer.hint-header-name プロパティの値を変更することで変更できます) をチェックし、ヒントリクエストヘッダーが見つかった場合は、ヘッダーに渡されたヒント値を使用してフィルターします。サービスインスタンス。

ヒントヘッダーが追加されていない場合、HintBasedServiceInstanceListSupplier はプロパティからのヒント値を使用してサービスインスタンスをフィルターします。

ヘッダーまたはプロパティによってヒントが設定されていない場合は、デリゲートによって提供されたすべてのサービスインスタンスが返されます。

フィルタリング中に、HintBasedServiceInstanceListSupplier は、metadataMap の hint キーに設定された一致する値を持つサービスインスタンスを検索します。一致するインスタンスが見つからない場合は、デリゲートによって提供されたすべてのインスタンスが返されます。

次のサンプル構成を使用してセットアップできます。

public class CustomLoadBalancerConfiguration {

    @Bean
    public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
            ConfigurableApplicationContext context) {
        return ServiceInstanceListSupplier.builder()
                    .withDiscoveryClient()
                    .withCaching()
                    .withHints()
                    .build(context);
    }
}

3.12. 負荷分散された HTTP リクエストを変換する

選択した ServiceInstance を使用して、負荷分散された HTTP リクエストを変換できます。

RestTemplate の場合、次のように LoadBalancerRequestTransformer を実装して定義する必要があります。

@Bean
public LoadBalancerRequestTransformer transformer() {
    return new LoadBalancerRequestTransformer() {
        @Override
        public HttpRequest transformRequest(HttpRequest request, ServiceInstance instance) {
            return new HttpRequestWrapper(request) {
                @Override
                public HttpHeaders getHeaders() {
                    HttpHeaders headers = new HttpHeaders();
                    headers.putAll(super.getHeaders());
                    headers.add("X-InstanceId", instance.getInstanceId());
                    return headers;
                }
            };
        }
    };
}

WebClient の場合、次のように LoadBalancerClientRequestTransformer を実装して定義する必要があります。

@Bean
public LoadBalancerClientRequestTransformer transformer() {
    return new LoadBalancerClientRequestTransformer() {
        @Override
        public ClientRequest transformRequest(ClientRequest request, ServiceInstance instance) {
            return ClientRequest.from(request)
                    .header("X-InstanceId", instance.getInstanceId())
                    .build();
        }
    };
}

複数のトランスフォーマが定義されている場合、Bean が定義されている順序で適用されます。または、LoadBalancerRequestTransformer.DEFAULT_ORDER または LoadBalancerClientRequestTransformer.DEFAULT_ORDER を使用して順序を指定することもできます。

3.13. Spring Cloud LoadBalancer スターター

Spring Boot アプリに Spring Cloud LoadBalancer を簡単に追加できるスターターも提供しています。これを使用するには、ビルドファイルの Spring Cloud 依存関係に org.springframework.cloud:spring-cloud-starter-loadbalancer を追加するだけです。

Spring Cloud LoadBalancer スターターには、Spring Boot キャッシングおよびエヴィクター [GitHub] (英語) が含まれます。

3.14. 独自の Spring Cloud LoadBalancer 構成を渡す

次のように、@LoadBalancerClient アノテーションを使用して、ロードバランサークライアントの名前と構成クラスを渡して、独自のロードバランサークライアント構成を渡すこともできます。

@Configuration
@LoadBalancerClient(value = "stores", configuration = CustomLoadBalancerConfiguration.class)
public class MyConfiguration {

    @Bean
    @LoadBalanced
    public WebClient.Builder loadBalancedWebClientBuilder() {
        return WebClient.builder();
    }
}
独自の LoadBalancer 構成での作業を容易にするために、ServiceInstanceListSupplier クラスに builder() メソッドを追加しました。
また、spring.cloud.loadbalancer.configurations プロパティの値を zone-preference に設定して ZonePreferenceServiceInstanceListSupplier をキャッシュとともに使用するか、health-check に設定して HealthCheckServiceInstanceListSupplier をキャッシュとともに使用することにより、デフォルトの構成の代わりに代替の事前定義された構成を使用することもできます。

この機能を使用すると、ユーザーが作成した、またはデフォルト設定をオーバーライドするための代替手段 (たとえば ZonePreferenceServiceInstanceListSupplier) として当社が提供した ServiceInstanceListSupplier または ReactorLoadBalancer のさまざまな実装をインスタンス化できます。

カスタム構成の例はここで見ることができます。

アノテーション value 引数 (上記の例では stores ) は、指定されたカスタム構成でリクエストを送信する必要があるサービスのサービス ID を指定します。

次の例に示すように、@LoadBalancerClients アノテーションを介して複数の構成 (複数のロードバランサークライアント用) を渡すこともできます。

@Configuration
@LoadBalancerClients({@LoadBalancerClient(value = "stores", configuration = StoresLoadBalancerClientConfiguration.class), @LoadBalancerClient(value = "customers", configuration = CustomersLoadBalancerClientConfiguration.class)})
public class MyConfiguration {

    @Bean
    @LoadBalanced
    public WebClient.Builder loadBalancedWebClientBuilder() {
        return WebClient.builder();
    }
}
@LoadBalancerClient または @LoadBalancerClients 構成引数として渡すクラスは、@Configuration のアノテーションが付けられていないか、コンポーネントのスキャン範囲外である必要があります。
独自の構成を作成する場合、CachingServiceInstanceListSupplier または HealthCheckServiceInstanceListSupplier を使用する場合は、両方ではなくどちらか一方を使用し、ネットワーク経由でインスタンスを取得するサプライヤーの直後の階層(たとえば DiscoveryClientServiceInstanceListSupplier など)に、他のフィルタリングサプライヤーよりも前に配置するようにしてください。

3.15. Spring Cloud LoadBalancer ライフサイクル

カスタム LoadBalancer 構成を使用して登録すると便利な Bean の型の 1 つは LoadBalancerLifecycle です。

LoadBalancerLifecycle Bean は、onStart(Request<RC> request)onStartRequest(Request<RC> request, Response<T> lbResponse)onComplete(CompletionContext<RES, T, RC> completionContext) という名前のコールバックメソッドを提供します。これを実装して、ロードバランシングの前後に実行するアクションを指定する必要があります。

onStart(Request<RC> request) は Request オブジェクトをパラメーターとして受け取ります。これには、ダウンストリームクライアントのリクエストやヒントなど、適切なインスタンスを選択するために使用されるデータが含まれています。onStartRequest は、Request オブジェクトに加えて、Response<T> オブジェクトもパラメーターとして受け取ります。一方、CompletionContext オブジェクトは onComplete(CompletionContext<RES, T, RC> completionContext) メソッドに提供されます。これには、選択したサービスインスタンス、そのサービスインスタンスに対して実行されたリクエストの Status、(利用可能な場合) ダウンストリームクライアントに返されたレスポンス、(例外が発生した場合) 対応する Throwable を含む LoadBalancer Response が含まれます。

supports(Class requestContextClass, Class responseClass, Class serverTypeClass) メソッドを使用すると、問題のプロセッサーが指定された型のオブジェクトを処理するかどうかを判断できます。ユーザーによってオーバーライドされていない場合は、true を返します。

前述のメソッド呼び出しでは、RC は RequestContext 型を意味し、RES はクライアントレスポンス型を意味し、T は返されたサーバー型を意味します。

3.16. Spring Cloud LoadBalancer 統計

MicrometerStatsLoadBalancerLifecycle と呼ばれる LoadBalancerLifecycle Bean が提供されており、これは Micrometer を使用して負荷分散された呼び出しの統計を提供します。

この Bean をアプリケーションコンテキストに追加するには、spring.cloud.loadbalancer.stats.micrometer.enabled の値を true に設定し、MeterRegistry を使用できるようにします (たとえば、プロジェクトに Spring Boot Actuator を追加します)。

MicrometerStatsLoadBalancerLifecycle は次のメーターを MeterRegistry に登録します。

  • loadbalancer.requests.active: 任意のサービスインスタンスの現在アクティブなリクエストの数を監視できるゲージ (サービスインスタンスデータはタグ経由で利用可能)。

  • loadbalancer.requests.success: 基礎となるクライアントにレスポンスを渡して終了した、負荷分散されたリクエストの実行時間を測定するタイマー。

  • loadbalancer.requests.failed: 例外で終了した負荷分散されたリクエストの実行時間を測定するタイマー。

  • loadbalancer.requests.discard: 破棄された負荷分散リクエスト、つまりリクエストを実行するサービスインスタンスが LoadBalancer によって取得されていないリクエストの数を測定するカウンター。

サービスインスタンス、リクエストデータ、レスポンスデータに関する追加情報は、利用可能な場合には常にタグを介してメトリクスに追加されます。

BlockingLoadBalancerClient などの一部の実装では、引数からジェネリクス型を確立し、型を判断してデータを読み取ることができない可能性があるため、リクエストデータとレスポンスデータが利用できない場合があります。
特定のメーターに少なくとも 1 つのレコードが追加されると、メーターはレジストリに登録されます。
MeterFilters を追加することで、これらのメトリクスの動作をさらに構成できます ( 公開パーセンタイルやヒストグラム (英語) の追加など)。

3.17. 個別の LoadBalancerClients の構成

個々のロードバランサークライアントは、異なるプレフィックス spring.cloud.loadbalancer.clients.<clientId>. を使用して個別に構成できます。clientId はロードバランサーの名前です。デフォルトの構成値は spring.cloud.loadbalancer. 名前空間で設定でき、優先されるクライアント固有の値とマージされます。

例 5: application.yml
spring:
  cloud:
    loadbalancer:
      health-check:
        initial-delay: 1s
      clients:
        myclient:
          health-check:
            interval: 30s

上記の例では、initial-delay=1s および interval=30s とマージされたヘルスチェック @ConfigurationProperties オブジェクトが生成されます。

クライアントごとの構成プロパティは、次のグローバルなプロパティを除き、ほとんどのプロパティで機能します。

  • spring.cloud.loadbalancer.enabled - 負荷分散をグローバルに有効または無効にします

  • spring.cloud.loadbalancer.retry.enabled - 負荷分散された再試行をグローバルに有効または無効にします。グローバルに有効にしても、client -prefixed プロパティを使用して特定のクライアントの再試行を無効にすることはできますが、その逆はできません。

  • spring.cloud.loadbalancer.cache.enabled - LoadBalancer キャッシュをグローバルに有効または無効にします。グローバルに有効にした場合でも、ServiceInstanceListSupplier デリゲート階層に CachingServiceInstanceListSupplier を含まないカスタム構成を作成することで、特定のクライアントのキャッシュを無効にすることができますが、その逆はできません。

  • spring.cloud.loadbalancer.stats.micrometer.enabled - LoadBalancer Micrometer メトリクスをグローバルに有効または無効にします

すでに使用されている場所にマップされ、clients キーワードを使用せずにクライアントごとに異なる値を指定できるプロパティ ( hintshealth-check.path など) については、ライブラリの下位互換性を維持するためにその動作が維持されています。次のメジャーリリースで変更される予定です。
4.0.4 から、LoadBalancerProperties に callGetWithRequestOnDelegates フラグを導入しました。このフラグが true に設定されている場合、ServiceInstanceListSupplier#get(Request request) メソッドが実装され、そのメソッドをまだ実装していない DelegatingServiceInstanceListSupplier から割り当て可能なクラスで delegate.get(request) が呼び出されます。ただし、CachingServiceInstanceListSupplier と HealthCheckServiceInstanceListSupplier は除外されます。これらは、リクエストベースのフィルタリングが行われる前に、ネットワーク経由でインスタンスの取得を実行するサプライヤーの直後のインスタンスサプライヤー階層に配置する必要があります。4.0.x の場合、フラグはデフォルトで false に設定されていますが、4.1.0 以降はデフォルトで true に設定されます。

3.18. AOT およびネイティブイメージのサポート

4.0.0 以降、Spring Cloud LoadBalancer は Spring AOT 変換とネイティブイメージをサポートします。ただし、この機能を使用するには、LoadBalancerClient サービス ID を明示的に定義する必要があります。これを行うには、@LoadBalancerClient アノテーションの value または name 属性を使用するか、spring.cloud.loadbalancer.eager-load.clients プロパティの値として使用します。

4. Spring Cloud Circuit Breaker

4.1. 導入

Spring Cloud サーキットブレーカーは、さまざまなサーキットブレーカー実装にわたる抽象化を提供します。アプリケーションで使用する一貫した API が提供されるため、開発者はアプリケーションのニーズに最適なサーキットブレーカーの実装を選択できます。

4.1.1. サポートされている実装

Spring Cloud は、次のサーキットブレーカーの実装をサポートしています。

4.2. コアコンセプト

コード内にサーキットブレーカーを作成するには、CircuitBreakerFactory API を使用できます。Spring Cloud Circuit Breaker スターターをクラスパスに含めると、この API を実装する Bean が自動的に作成されます。次の例は、この API の使用方法の簡単な例を示しています。

@Service
public static class DemoControllerService {
    private RestTemplate rest;
    private CircuitBreakerFactory cbFactory;

    public DemoControllerService(RestTemplate rest, CircuitBreakerFactory cbFactory) {
        this.rest = rest;
        this.cbFactory = cbFactory;
    }

    public String slow() {
        return cbFactory.create("slow").run(() -> rest.getForObject("/slow", String.class), throwable -> "fallback");
    }

}

CircuitBreakerFactory.create API は、CircuitBreaker というクラスのインスタンスを作成します。run メソッドは Supplier と Function を受け取ります。Supplier は、サーキットブレーカーにラップするコードです。Function は、サーキットブレーカーが作動した場合に実行されるフォールバックです。この関数には、フォールバックをトリガーした Throwable が渡されます。フォールバックを提供したくない場合は、オプションでフォールバックを除外できます。

4.2.1. リアクティブコードのサーキットブレーカー

プロジェクト Reactor がクラスパス上にある場合は、リアクティブコードに ReactiveCircuitBreakerFactory を使用することもできます。次の例は、その方法を示しています。

@Service
public static class DemoControllerService {
    private ReactiveCircuitBreakerFactory cbFactory;
    private WebClient webClient;


    public DemoControllerService(WebClient webClient, ReactiveCircuitBreakerFactory cbFactory) {
        this.webClient = webClient;
        this.cbFactory = cbFactory;
    }

    public Mono<String> slow() {
        return webClient.get().uri("/slow").retrieve().bodyToMono(String.class).transform(
        it -> cbFactory.create("slow").run(it, throwable -> return Mono.just("fallback")));
    }
}

ReactiveCircuitBreakerFactory.create API は、ReactiveCircuitBreaker というクラスのインスタンスを作成します。run メソッドは、Mono または Flux を受け取り、それをサーキットブレーカーでラップします。オプションでフォールバック Function をプロファイリングできます。フォールバック Function は、サーキットブレーカーが作動し、障害の原因となった Throwable が渡された場合に呼び出されます。

4.3. 構成

型 Customizer の Bean を作成することで、サーキットブレーカーを構成できます。Customizer インターフェースには、Object を使用してカスタマイズする単一のメソッド ( customize と呼ばれる) があります。

特定の実装をカスタマイズする方法の詳細については、次のドキュメントを参照してください。

Resilience4JCircuitBreaker などの一部の CircuitBreaker 実装は、CircuitBreaker#run が呼び出されるたびに customize メソッドを呼び出します。非効率的になる可能性があります。その場合は、CircuitBreaker#once メソッドを使用できます。これは、たとえば、Resilience4j のイベントを使用する (英語) 場合など、customize を何度も呼び出すことが意味がない場合に役立ちます。

次の例は、各 io.github.resilience4j.circuitbreaker.CircuitBreaker がイベントを消費する方法を示しています。

Customizer.once(circuitBreaker -> {
  circuitBreaker.getEventPublisher()
    .onStateTransition(event -> log.info("{}: {}", event.getCircuitBreakerName(), event.getStateTransition()));
}, CircuitBreaker::getName)

5. CachedRandomPropertySource

Spring Cloud Context は、キーに基づいてランダムな値をキャッシュする PropertySource を提供します。キャッシュ機能以外では、Spring Boot の RandomValuePropertySource [GitHub] (英語) と同じように動作します。このランダム値は、Spring アプリケーションコンテキストが再起動した後でも一貫したランダム値が必要な場合に便利です。プロパティ値は cachedrandom.[yourkey].[type] の形式をとり、yourkey はキャッシュ内のキーです。type 値には、Spring Boot の RandomValuePropertySource でサポートされる任意の型を指定できます。

myrandom=${cachedrandom.appname.value}

6. セキュリティ

6.1. シングルサインオン

OAuth2 SSO およびリソースサーバー機能はすべて、バージョン 1.3 の Spring Boot に移行されました。ドキュメントは Spring Boot ユーザーガイドにあります。

6.1.1. クライアントトークンリレー

アプリが OAuth2 クライアントに面するユーザー (つまり、@EnableOAuth2Sso または @EnableOAuth2Client を宣言している) である場合、そのアプリは Spring Boot からのリクエストスコープに OAuth2ClientContext を持ちます。このコンテキストとオートワイヤーされた OAuth2ProtectedResourceDetails から独自の OAuth2RestTemplate を作成すると、コンテキストは常にアクセストークンをダウンストリームに転送し、有効期限が切れた場合はアクセストークンを自動的にリフレッシュします。(Spring Security、Spring Boot の特長です。)

6.1.2. リソースサーバートークンリレー

アプリに @EnableResourceServer がある場合は、受信トークンをダウンストリームで他のサービスに中継することをお勧めします。RestTemplate を使用してダウンストリームサービスに接続する場合、これは適切なコンテキストを使用してテンプレートを作成する方法だけの問題です。

サービスが受信トークンの認証に UserInfoTokenServices を使用している場合 (つまり、security.oauth2.user-info-uri 構成を使用している場合)、オートワイヤーされた OAuth2ClientContext を使用して OAuth2RestTemplate を簡単に作成できます (バックエンドコードに到達する前に認証プロセスによって設定されます)。同様に (Spring Boot 1.4 を使用する場合)、UserInfoRestTemplateFactory を挿入し、構成内でその OAuth2RestTemplate を取得できます。例:

MyConfiguration.java
@Bean
public OAuth2RestTemplate restTemplate(UserInfoRestTemplateFactory factory) {
    return factory.getUserInfoRestTemplate();
}

この Rest テンプレートには、認証フィルターで使用されるものと同じ OAuth2ClientContext (リクエストスコープ) が含まれるため、それを使用して同じアクセストークンでリクエストを送信できます。

アプリが UserInfoTokenServices を使用していなくてもクライアントである場合 (つまり、@EnableOAuth2Client または @EnableOAuth2Sso を宣言している場合)、Spring Security Cloud では、ユーザーが @AutowiredOAuth2Context から作成した OAuth2RestOperations もトークンを転送します。この機能はデフォルトで MVC ハンドラーインターセプターとして実装されるため、Spring MVC でのみ動作します。MVC を使用していない場合は、AccessTokenContextRelay をラップするカスタムフィルターまたは AOP インターセプターを使用して、同じ機能を提供できます。

以下は、他の場所で作成されたオートワイヤーされた REST テンプレートの使用を示す基本的な例です ("foo.com" は、周囲のアプリと同じトークンを受け入れるリソースサーバーです)。

MyController.java
@Autowired
private OAuth2RestOperations restTemplate;

@RequestMapping("/relay")
public String relay() {
    ResponseEntity<String> response =
      restTemplate.getForEntity("https://foo.com/bar", String.class);
    return "Success! (" + response.getBody() + ")";
}

トークンを転送したくない場合 (トークンを送信したクライアントではなく、自分自身として動作する可能性があるため、これは有効な選択です)、必要なのは、デフォルトのもの。

偽のクライアントは、OAuth2ClientContext が利用可能な場合はそれを使用するインターセプターも選択するため、RestTemplate が実行する場所であればどこでもトークンリレーを実行する必要があります。

7. プロパティの構成

Spring Cloud Commons に関連するすべての構成プロパティのリストを表示するには、付録ページを確認してください。