1. 概要

Spring Cloudは、堅牢なクラウドアプリケーションを構築するためのフレームワークです。 このフレームワークは、分散環境に移行するときに直面する一般的な問題の多くにソリューションを提供することにより、アプリケーションの開発を容易にします。

マイクロサービスアーキテクチャで実行されるアプリケーションは、開発、デプロイ、およびメンテナンスを簡素化することを目的としています。 アプリケーションの分解された性質により、開発者は一度に1つの問題に集中できます。 システムの他の部分に影響を与えることなく、改善を導入できます。

一方、マイクロサービスアプローチを採用すると、さまざまな課題が発生します。

  • 柔軟で、変更時にサービスを再構築する必要がないように構成を外部化する
  • サービスディスカバリ
  • さまざまなホストにデプロイされたサービスの複雑さを隠す

この記事では、構成サーバー、検出サーバー、ゲートウェイサーバー、ブックサービス、そして最後に評価サービスの5つのマイクロサービスを構築します。 これらの5つのマイクロサービスは、クラウド開発を開始し、前述の課題に対処するための強固なベースアプリケーションを形成します。

2. 構成サーバー

クラウドアプリケーションを開発する場合、1つの問題は、構成を維持してサービスに配布することです。 サービスを水平方向に拡張する前に各環境の構成に時間を費やしたり、構成をアプリケーションに組み込むことでセキュリティ違反のリスクを冒したりすることは本当に望ましくありません。

これを解決するために、すべての構成を単一のGitリポジトリに統合し、それをすべてのアプリケーションの構成を管理する1つのアプリケーションに接続します。 非常に単純な実装を設定します。

詳細とより複雑な例を確認するには、 Spring CloudConfigurationの記事をご覧ください。

2.1. 設定

https://start.spring.io に移動し、MavenおよびSpringBoot2.2.xを選択します。

アーティファクトを「configに設定します。 依存関係セクションで、「構成サーバー」を検索し、そのモジュールを追加します。 次に、生成ボタンを押すと、事前構成されたプロジェクトが含まれているzipファイルをダウンロードして準備が整います。

または、 Spring Boot プロジェクトを生成し、POMファイルにいくつかの依存関係を手動で追加することもできます。

これらの依存関係は、すべてのプロジェクト間で共有されます。

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.0</version>
    <relativePath/>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies> 

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR4</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

構成サーバーの依存関係を追加しましょう。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>

参考までに、Maven Centralで最新バージョンを見つけることができます( spring-cloud-dependencies、test、config-server )。

2.2. SpringConfig

構成サーバーを有効にするには、メインアプリケーションクラスにいくつかの注釈を追加する必要があります。

@SpringBootApplication
@EnableConfigServer
public class ConfigApplication {...}

@EnableConfigServer は、アプリケーションを構成サーバーに変えます。

2.3. プロパティ

src / main /resourcesapplication.propertiesを追加しましょう。

server.port=8081
spring.application.name=config

spring.cloud.config.server.git.uri=file://${user.home}/application-config

構成サーバーの最も重要な設定は、git.uriパラメーターです。 これは現在、Windowsでは c:\ Users \ {username} \ に、*nixでは/ Users / {username}/に解決される相対ファイルパスに設定されています。 このプロパティは、他のすべてのアプリケーションのプロパティファイルが保存されているGitリポジトリを指します。 必要に応じて、絶対ファイルパスに設定できます。

ヒント:Windowsマシンでは、値の前に「file:///」を付け、* nixでは「file://」を使用します。

2.4. Gitリポジトリ

spring.cloud.config.server.git.uri で定義されたフォルダーに移動し、フォルダーapplication-configを追加します。 そのフォルダにCDを挿入し、 gitinitと入力します。 これにより、ファイルを保存してその変更を追跡できるGitリポジトリが初期化されます。

2.5. 走る

構成サーバーを実行して、機能していることを確認しましょう。 コマンドラインからmvnspring-boot:runと入力します。 これにより、サーバーが起動します。

サーバーが実行されていることを示す次の出力が表示されます。

Tomcat started on port(s): 8081 (http)

2.6. ブートストラップ構成

以降のサーバーでは、アプリケーションのプロパティをこの構成サーバーで管理する必要があります。 そのためには、実際に鶏が先か卵が先かを少し行う必要があります。このサーバーとの通信方法を知っている各アプリケーションのプロパティを構成します。

これはブートストラッププロセスであり、これらのアプリのそれぞれにbootstrap.propertiesというファイルがあります。 application.properties と同じようにプロパティが含まれますが、ひねりが加えられています。

親SpringApplicationContext は最初にbootstrap.propertiesをロードします。これは、ConfigServerがapplication.propertiesのプロパティの管理を開始できるようにするために重要です。 暗号化されたアプリケーションのプロパティも復号化するのは、この特別なApplicationContextです。

これらのプロパティファイルを区別しておくのが賢明です。bootstrap.properties は構成サーバーを準備するためのものであり、application.propertiesはアプリケーションに固有のプロパティ用です。 ただし、技術的には、アプリケーションのプロパティをbootstrap.propertiesに配置することは可能です。

最後に、Config Serverがアプリケーションのプロパティを管理しているので、なぜapplication.propertiesがあるのか疑問に思うかもしれません。 答えは、これらはおそらくConfigServerにはないデフォルト値としてまだ便利であるということです。

3. 発見

構成が処理されたので、すべてのサーバーが相互に検出できるようにする方法が必要です。 Eureka 検出サーバーをセットアップすることにより、この問題を解決します。 アプリケーションは任意のIP/ポートの組み合わせで実行できるため、アプリケーションアドレスルックアップとして機能できる中央アドレスレジストリが必要です。

新しいサーバーがプロビジョニングされると、検出サーバーと通信し、そのアドレスを登録して、他のサーバーと通信できるようにします。 このようにして、他のアプリケーションは要求を行うときにこの情報を消費できます。

詳細とより複雑な検出の実装を確認するには、 SpringCloudEurekaの記事をご覧ください。

3.1. 設定

ここでも、start。spring.ioに移動します。 アーティファクトを「検出」に設定します。 「eurekaserver」を検索し、その依存関係を追加します。 「configclient」を検索し、その依存関係を追加します。 最後に、プロジェクトを生成します。

または、 Spring Boot プロジェクトを作成し、 POM の内容を構成サーバーからコピーして、次の依存関係を交換することもできます。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>

参考までに、バンドルはMaven Central( config-client、eureka-server )にあります。

3.2. SpringConfig

Java構成をメインクラスに追加しましょう。

@SpringBootApplication
@EnableEurekaServer
public class DiscoveryApplication {...}

@EnableEurekaServer は、 NetflixEurekaを使用してこのサーバーを検出サーバーとして構成します。 Spring Boot は、クラスパスに対する構成の依存関係を自動的に検出し、構成サーバーから構成を検索します。

3.3. プロパティ

次に、2つのプロパティファイルを追加します。

まず、bootstrap.propertiessrc/ main /resourcesに追加します。

spring.cloud.config.name=discovery
spring.cloud.config.uri=http://localhost:8081

これらのプロパティにより、検出サーバーは起動時に構成サーバーにクエリを実行できます。

次に、Discovery.propertiesをGitリポジトリに追加します

spring.application.name=discovery
server.port=8082

eureka.instance.hostname=localhost

eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

ファイル名はspring.application.nameプロパティと一致する必要があります。

さらに、このサーバーにデフォルトゾーンで動作していることを通知しています。これは、構成クライアントのリージョン設定と一致します。 また、別の検出インスタンスに登録しないようにサーバーに指示しています。

本番環境では、障害が発生した場合に冗長性を提供するためにこれらを複数用意し、その設定が当てはまります。

ファイルをGitリポジトリにコミットしましょう。 そうしないと、ファイルは検出されません。

3.4. 構成サーバーに依存関係を追加する

この依存関係を構成サーバーのPOMファイルに追加します。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

参考までに、バンドルはMaven Central( eureka-client )にあります。

これらのプロパティを、構成サーバーの src / main /resourcesにあるapplication.propertiesファイルに追加します。

eureka.client.region = default
eureka.client.registryFetchIntervalSeconds = 5
eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/

3.5. 走る

同じコマンドmvnspring-boot:runを使用して検出サーバーを起動します。 コマンドラインからの出力には、次のものが含まれている必要があります。

Fetching config from server at: http://localhost:8081
...
Tomcat started on port(s): 8082 (http)

構成サービスを停止して再実行します。 すべてが良好な場合、出力は次のようになります。

DiscoveryClient_CONFIG/10.1.10.235:config:8081: registering service...
Tomcat started on port(s): 8081 (http)
DiscoveryClient_CONFIG/10.1.10.235:config:8081 - registration status: 204

4. ゲートウェイ

構成と検出の問題が解決されたので、クライアントがすべてのアプリケーションにアクセスする際の問題がまだ発生しています。

すべてを分散システムに残す場合、クライアントでクロスオリジンリクエストを許可するには、複雑なCORSヘッダーを管理する必要があります。 これは、ゲートウェイサーバーを作成することで解決できます。 これは、クライアントからバックエンドサーバーへのリバースプロキシシャトルリクエストとして機能します。

ゲートウェイサーバーは、すべての応答を単一のホストから発信できるため、マイクロサービスアーキテクチャの優れたアプリケーションです。 これにより、CORSが不要になり、認証などの一般的な問題を処理するのに便利な場所が提供されます。

4.1. 設定

これで、ドリルがわかりました。 https://start.spring.ioに移動します。 アーティファクトを「ゲートウェイ」に設定します。 「zuul」を検索し、その依存関係を追加します。 「configclient」を検索し、その依存関係を追加します。 「eurekadiscovery」を検索し、その依存関係を追加します。 最後に、そのプロジェクトを生成します。

または、次の依存関係を使用して SpringBootアプリを作成することもできます。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>

参考までに、バンドルはMaven Central( config-client、eureka-client、zuul )にあります。

4.2. SpringConfig

構成をメインクラスに追加しましょう。

@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
@EnableFeignClients
public class GatewayApplication {...}

4.3. プロパティ

次に、2つのプロパティファイルを追加します。

src / main /resourcesbootstrap.properties

spring.cloud.config.name=gateway
spring.cloud.config.discovery.service-id=config
spring.cloud.config.discovery.enabled=true

eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/

Gitリポジトリのgateway.properties

spring.application.name=gateway
server.port=8080

eureka.client.region = default
eureka.client.registryFetchIntervalSeconds = 5

zuul.routes.book-service.path=/book-service/**
zuul.routes.book-service.sensitive-headers=Set-Cookie,Authorization
hystrix.command.book-service.execution.isolation.thread.timeoutInMilliseconds=600000

zuul.routes.rating-service.path=/rating-service/**
zuul.routes.rating-service.sensitive-headers=Set-Cookie,Authorization
hystrix.command.rating-service.execution.isolation.thread.timeoutInMilliseconds=600000

zuul.routes.discovery.path=/discovery/**
zuul.routes.discovery.sensitive-headers=Set-Cookie,Authorization
zuul.routes.discovery.url=http://localhost:8082
hystrix.command.discovery.execution.isolation.thread.timeoutInMilliseconds=600000

zuul.routes プロパティを使用すると、antURLマッチャーに基づいて特定のリクエストをルーティングするアプリケーションを定義できます。 私たちのプロパティは、 / book-service / ** で着信するすべてのリクエストを、book-serviceのspring.application.nameを持つアプリケーションにルーティングするようにZuulに指示します。 ]。 次に、Zuulは、アプリケーション名を使用して検出サーバーからホストを検索し、そのサーバーに要求を転送します。

リポジトリに変更をコミットすることを忘れないでください!

4.4. 走る

構成アプリケーションと検出アプリケーションを実行し、構成アプリケーションが検出サーバーに登録されるまで待ちます。 それらがすでに実行されている場合は、再起動する必要はありません。 それが完了したら、ゲートウェイサーバーを実行します。 ゲートウェイサーバーはポート8080で起動し、検出サーバーに登録する必要があります。 コンソールからの出力には、次のものが含まれている必要があります。

Fetching config from server at: http://10.1.10.235:8081/
...
DiscoveryClient_GATEWAY/10.1.10.235:gateway:8080: registering service...
DiscoveryClient_GATEWAY/10.1.10.235:gateway:8080 - registration status: 204
Tomcat started on port(s): 8080 (http)

簡単に犯しやすい間違いの1つは、構成サーバーがEurekaに登録される前にサーバーを起動することです。 この場合、次の出力のログが表示されます。

Fetching config from server at: http://localhost:8888

これは構成サーバーのデフォルトのURLとポートであり、構成要求が行われたときに検出サービスにアドレスがなかったことを示します。 数秒待ってから再試行してください。構成サーバーがEurekaに登録されると、問題は解決します。

5. ブックサービス

マイクロサービスアーキテクチャでは、ビジネス目標を達成するために、自由に多くのアプリケーションを作成できます。 多くの場合、エンジニアはサービスをドメインごとに分割します。 このパターンに従い、アプリケーション内の書籍のすべての操作を処理する書籍サービスを作成します。

5.1. 設定

もう1回。 https://start.spring.ioに移動します。 アーティファクトを「book-service」に設定します。 「web」を検索し、その依存関係を追加します。 「configclient」を検索し、その依存関係を追加します。 「eurekadiscovery」を検索し、その依存関係を追加します。 そのプロジェクトを生成します。

または、次の依存関係をプロジェクトに追加します。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

参考までに、バンドルはMaven Central( config-client、eureka-client、web )にあります。

5.2. SpringConfig

メインクラスを変更しましょう:

@SpringBootApplication
@EnableEurekaClient
@RestController
@RequestMapping("/books")
public class BookServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(BookServiceApplication.class, args);
    }

    private List<Book> bookList = Arrays.asList(
        new Book(1L, "Baeldung goes to the market", "Tim Schimandle"),
        new Book(2L, "Baeldung goes to the park", "Slavisa")
    );

    @GetMapping("")
    public List<Book> findAllBooks() {
        return bookList;
    }

    @GetMapping("/{bookId}")
    public Book findBook(@PathVariable Long bookId) {
        return bookList.stream().filter(b -> b.getId().equals(bookId)).findFirst().orElse(null);
    }
}

また、構成中に設定する値を返すために、RESTコントローラーとプロパティファイルによって設定されたフィールドを追加しました。

次に、POJOという本を追加しましょう。

public class Book {
    private Long id;
    private String author;
    private String title;

    // standard getters and setters
}

5.3. プロパティ

次に、2つのプロパティファイルを追加する必要があります。

src / main /resourcesbootstrap.properties

spring.cloud.config.name=book-service
spring.cloud.config.discovery.service-id=config
spring.cloud.config.discovery.enabled=true

eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/

Gitリポジトリのbook-service.properties

spring.application.name=book-service
server.port=8083

eureka.client.region = default
eureka.client.registryFetchIntervalSeconds = 5
eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/

リポジトリへの変更をコミットしましょう。

5.4. 走る

他のすべてのアプリケーションが開始したら、ブックサービスを開始できます。 コンソール出力は次のようになります。

DiscoveryClient_BOOK-SERVICE/10.1.10.235:book-service:8083: registering service...
DiscoveryClient_BOOK-SERVICE/10.1.10.235:book-service:8083 - registration status: 204
Tomcat started on port(s): 8083 (http)

起動したら、ブラウザを使用して、作成したばかりのエンドポイントにアクセスできます。 http:// localhost:8080 / book-service / booksに移動すると、outコントローラーに追加した2冊の本を含むJSONオブジェクトが返されます。 ポート8083でブックサービスに直接アクセスしていませんが、ゲートウェイサーバーを経由していることに注意してください。

6. 評価サービス

書籍サービスと同様に、評価サービスは、評価に関連する操作を処理するドメイン駆動型サービスになります。

6.1. 設定

もう1回。 https://start.spring.ioに移動します。 アーティファクトを「rating-service」に設定します。 「web」を検索し、その依存関係を追加します。 「configclient」を検索し、その依存関係を追加します。 eurekadiscoveryを検索し、その依存関係を追加します。 次に、そのプロジェクトを生成します。

または、次の依存関係をプロジェクトに追加します。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

参考までに、バンドルはMaven Central( config-client、eureka-client、web )にあります。

6.2. SpringConfig

メインクラスを変更しましょう:

@SpringBootApplication
@EnableEurekaClient
@RestController
@RequestMapping("/ratings")
public class RatingServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(RatingServiceApplication.class, args);
    }

    private List<Rating> ratingList = Arrays.asList(
        new Rating(1L, 1L, 2),
        new Rating(2L, 1L, 3),
        new Rating(3L, 2L, 4),
        new Rating(4L, 2L, 5)
    );

    @GetMapping("")
    public List<Rating> findRatingsByBookId(@RequestParam Long bookId) {
        return bookId == null || bookId.equals(0L) ? Collections.EMPTY_LIST : ratingList.stream().filter(r -> r.getBookId().equals(bookId)).collect(Collectors.toList());
    }

    @GetMapping("/all")
    public List<Rating> findAllRatings() {
        return ratingList;
    }
}

また、構成中に設定する値を返すために、RESTコントローラーとプロパティファイルによって設定されたフィールドを追加しました。

評価POJOを追加しましょう:

public class Rating {
    private Long id;
    private Long bookId;
    private int stars;

    //standard getters and setters
}

6.3. プロパティ

次に、2つのプロパティファイルを追加する必要があります。

src / main /resourcesbootstrap.properties

spring.cloud.config.name=rating-service
spring.cloud.config.discovery.service-id=config
spring.cloud.config.discovery.enabled=true

eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/

Gitリポジトリのrating-service.properties

spring.application.name=rating-service
server.port=8084

eureka.client.region = default
eureka.client.registryFetchIntervalSeconds = 5
eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/

リポジトリへの変更をコミットしましょう。

6.4. 走る

他のすべてのアプリケーションが開始したら、評価サービスを開始できます。 コンソール出力は次のようになります。

DiscoveryClient_RATING-SERVICE/10.1.10.235:rating-service:8083: registering service...
DiscoveryClient_RATING-SERVICE/10.1.10.235:rating-service:8083 - registration status: 204
Tomcat started on port(s): 8084 (http)

起動したら、ブラウザを使用して、作成したばかりのエンドポイントにアクセスできます。 http:// localhost:8080 /rating-service /ratings / all に移動すると、すべての評価を含むJSONが返されます。 ポート8084で評価サービスに直接アクセスしているのではなく、ゲートウェイサーバーを経由していることに注意してください。

7. 結論

これで、SpringCloudのさまざまな部分を機能するマイクロサービスアプリケーションに接続できるようになりました。 これは、より複雑なアプリケーションの構築を開始するために使用できるベースを形成します。

いつものように、このソースコードはGitHubにあります。