前回はAmazon SQSの概要やアプリケーションにSQSを組み込んだ構成のパターンを説明し、実際にコンソール上からキューを作成しました。今回は、下記のようにSQSへキューを送信するProducerアプリケーションを「Spring Cloud AWS」を使って実装していきます。
本連載の第12回でも説明しましたが、Spring Cloud AWSはAWSのサービスに対してサポートを提供するものです。SQSに関しては、org.springframework.cloud.aws.messaging.core.QueueMessagingTemplateを使用したメッセージ送受信機能や、 org.springframework.cloud.aws.messaging.listener.annotation.SqsListenerを使用したメッセージポーリング機能を提供しています。
なお、実際に作成したアプリケーションはGitHub上にコミットしています。以降で紹介するソースコードでは、import文など本質的でない記述を省略している部分があるので、実行コードを作成する場合は、適宜GitHub上のソースコードも参照してください。
クラスの実装に入る前に
Spring Cloud AWSを使用するには、まず、Mavenプロジェクトのpom.xmlでspring-cloud-starter-awsのライブラリを定義します。加えて、SQSを利用するにはspring-cloud-starter-aws-messagingのライブラリを追加してください。
さらに、リクエストを受け付け、パラメータをSQSに送信する処理を実装するので、spring-boot-starter-webを追加し、モデルオブジェクトを簡素化するために、Lombokライブラリも追加します。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-aws</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-aws-messaging</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
それでは、Producerアプリケーションの実装に進みます。今回作成するProducerアプリケーションの構成は以下の通りです。
コンポーネント | 説明 | 必須 |
---|---|---|
WebApp | SpringBootアプリケーションを実行する起動クラス | ◯ |
MvcConfig | SpringMVCの設定を行うクラス | ― |
DomainConfig | サービス・インフラストラクチャレイヤの設定を行うクラス | ― |
SqsConfig | SQSへの接続に関する設定クラス | ◯ |
SampleRestController | リクエストを受け取り、SampleRepositoryを呼び出して、JSONレスポンスを返却するController | ◯ |
SampleRepository | QueueMessagingTemplateを使って、SQSへメッセージ送信を行うクラス | ◯ |
Sample | SampleRepositoryの永続化データモデル | ― |
以降、各々のクラスについて解説を進めていきますが、事前に準備が必要です。
まず、AWSコンソールでアプリケーション用のユーザーを作成し、AWS公式ページ「設定ファイルと認証情報ファイル」を参考にユーザーホームフォルダに.awsディレクトリを作成してください。同ディレクトリに、「credential」というファイル名で、CSV形式の認証キーに記載しているユーザー認証情報を、以下の形式で保存します。
[default]
aws_access_key_id=XXXXXXXXXXXXXXXX
aws_secret_access_key=YYYYYYYYYYYYYYYYYYYYYYYYYYYYY
上記のクレデンシャルを持つユーザーは、SQSへの接続権限を持っている必要があります。以下のように、AWSコンソールで「IAM」サービスメニューから、ユーザーにSQSのアクセス権限を付与しておいてください。
SQSのアクセス権限を付与しておく |
クラスの実装
それでは、クラスを実装していきましょう。まず最初に、SpringBoot起動クラスと各種設定クラスを作成します。
@SpringBootApplicaitonアノテーションが付与された起動クラスは、同一パッケージにある@Configurationアノテーションが付与された設定クラスと、設定クラス内で@ComponentScanされたパッケージにあるクラスを読み取ります。今回は、目的に応じて以下の3つに分類して設定クラスを作成します。
- SpringMVCの設定クラス:MvcConfigクラス
- サービス・インフラストラクチャレイヤ設定クラス:DomainConfigクラス
- SQSの接続を行う設定クラス:SqsConfigクラス
設定クラスは必ずしも複数である必要はなく、1つにまとめても動作上問題ありません。ただし、クラス名と役割を対応付けて作成しておいたほうが、後々混乱することなく、クラス名から設定内容を識別できるのでベターでしょう。
package org.debugroom.mynavi.sample.aws.sqs.config;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class WebApp {
public static void main(String[] args) {
SpringApplication.run(WebApp.class, args);
}
}
今回リクエストを受け付けるControllerは、RestControllerとして作成します。そのため、同一パッケージに配置するMvcConfigクラスでは、org.springframework.web.servlet.config.annotation.WebMvcConfigurerを継承し、Controllerクラスのあるパッケージをコンポーネントスキャンする設定を加えておくだけでOKです。
package org.debugroom.mynavi.sample.aws.sqs.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@ComponentScan("org.debugroom.mynavi.sample.aws.sqs.app.web")
public class MvcConfig implements WebMvcConfigurer {
}
SQSに対してメッセージを送信するコンポーネントは、メッセージを永続化するRepositoryとして実装します。DomainConfigでは、Repositoryの実装クラスのあるパッケージをコンポーネントスキャンする設定を加えておくだけでOKです。
package org.debugroom.mynavi.sample.aws.sqs.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("org.debugroom.mynavi.sample.aws.sqs.domain")
public class DomainConfig {
}
次に、SQSへの接続情報を設定するSqsConfigですが、AmazonSDKで提供されているAmazonSQSAsyncを設定した、QueueMessagingTemplateクラスをBean定義します。また、AmazonSQSAsyncの内部で設定されるEndpointConfigurationには、前回作成したSQSキューがあるリージョンとエンドポイントを設定してBean定義しておきます。
package org.debugroom.mynavi.sample.aws.sqs.config;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.sqs.AmazonSQSAsync;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SqsConfig {
@Value("${queue.endpoint}")
private String queueEndpoint;
@Value("${cloud.aws.region.static}")
private String region;
@Autowired
AmazonSQSAsync amazonSQSAsync;
@Bean
public AwsClientBuilder.EndpointConfiguration endpointConfiguration(){
return new AwsClientBuilder.EndpointConfiguration(queueEndpoint, region);
}
@Bean
public QueueMessagingTemplate queueMessagingTemplate(){
return new QueueMessagingTemplate(amazonSQSAsync);
}
}
上記の設定では、第26回でも説明したように、Spring Cloud AWSがcom.amazonaws.auth.DefaultAWSCredentialsProviderChainを利用して、AWSの認証情報を取得します。アクセスキーなどは設定せずに、開発端末下だけで有効化されるapplication-dev.ymlで、cloud.aws.credentials.profileに空白を、instaceProfileに「false」を設定しておきましょう。
また、リージョンの自動検出をOFFにするよう、cloud.aws.region.autoに「false」を、今回アプリケーションが実行されるリージョンを「cloud.aws.region.static」に手動設定しておきます。
applicaiton-dev.yml
cloud:
aws:
credentials:
profileName:
instanceProfile: false
region:
auto: false
static: ap-northeast-1
また、applicaiton.ymlでは、アプリケーションのスタック名自動検出の無効化とキューのエンドポイントを設定しておきます。
application.yml
cloud:
aws:
stack:
auto: false
queue:
endpoint: https://sqs.ap-northeast-1.amazonaws.com/
続いて、リクエストを受け付けるControllerを実装しましょう。
SQSへのメッセージ送信が実装されているSampleRepositoryをを呼び出し、文字列のJSONデータを返却する処理を実装します。
package org.debugroom.mynavi.sample.aws.sqs.app.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.debugroom.mynavi.sample.aws.sqs.domain.model.Sample;
import org.debugroom.mynavi.sample.aws.sqs.domain.repository.SampleRepository;
@RestController
@RequestMapping("api/v1")
public class SampleRestController {
@Autowired
SampleRepository sampleRepository;
@GetMapping("/batch")
public String batch(String message){
sampleRepository.save(
Sample.builder()
.message(message)
.build());
return "Queue accepted.";
}
}
最後に、実際にSQSキューへメッセージを送信するRepositoryクラスです。インジェクションしたQueueMessagingTemplate#convertAndSendメソッドを呼び出すだけですが、第1引数には前回作成したキューの名称を、第2引数にメッセージ本体となる文字列を設定します。
package org.debugroom.mynavi.sample.aws.sqs.domain.repository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate;
import org.springframework.stereotype.Component;
import org.debugroom.mynavi.sample.aws.sqs.domain.model.Sample;
@Component
public class SampleRepositoryImpl implements SampleRepository{
@Autowired
QueueMessagingTemplate queueMessagingTemplate;
@Override
public void save(Sample sample) {
queueMessagingTemplate.convertAndSend("MynaviSampleSqsQueue", sample.getMessage());
}
}
起動クラスを実行してアプリケーションを起動し、コマンドラインなどからHTTPリクエストを送信してControllerを呼び出します。正常に完了すると、以下のようにControllerから完了メッセージが返却されます。
>curl http://localhost:8080/api/v1/batch?message=test
Queue accepted.
AWSコンソール上で、前回作成したキューを選択し、「キュー操作」から「メッセージの表示・削除」を選択すると、キューにメッセージが蓄積されていることが確認できます。
これで、メッセージを送信するProducerアプリケーションが実装できました。次回は、このメッセージを受信するConsumerアプリケーションから実行されるBatch処理を、SpringBatchを使って作成します。
著者紹介
川畑 光平(KAWABATA Kohei) - NTTデータ 課長代理
金融機関システム業務アプリケーション開発・システム基盤担当を経て、現在はソフトウェア開発自動化関連の研究開発・推進に従事。
Red Hat Certified Engineer、Pivotal Certified Spring Professional、AWS Certified Solutions Architect Professional等の資格を持ち、アプリケーション基盤・クラウドなどさまざまな開発プロジェクト支援にも携わる。2019 APN AWS Top Engineers & Ambassadors選出。
本連載の内容に対するご意見・ご質問は Facebook まで。