前回に引き続き、今回もSpring SessionとSpring Data Redisを使ってセッション情報を共有するアプリケーションを実装していきます。
アプリケーションコンポーネントの実装
では早速、アプリケーションコンポーネントを実装してみましょう。
具体的には、@SessionScopeアノテーションを付与し、セッションに格納するJavaオブジェクトを実装することになります。またその際には、コンポーネントスキャンの対象となるように@Componentを付与し、前回設定クラスで実装した@ComponentScanで指定したパッケージ配下に作成してください。
今回実装するJavaオブジェクトは、セッションが共有することがわかるように、変数として「ホスト名」と「最終更新日時」を持つようにしています。コードは以下の通りです。
package org.debugroom.mynavi.sample.aws.elasticache.app.web.model;
import java.io.Serializable;
import java.util.Date;
import org.springframework.stereotype.Component;
import org.springframework.web.context.annotation.SessionScope;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@SessionScope
@Component
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
public class SampleSession implements Serializable {
private String host;
private Date lastUpdatedAt;
}
Controllerでは、リクエストを受け取り、上記のオブジェクトの変数であるホスト名と最新日時を更新した後、セッションに保存して結果をテンプレートに渡す処理を実装します。オブジェクトには@SessionScopeアノテーションが付与されているので、Controllerクラスで対象オブジェクトを@Autowiredすれば、固有のセッションを取得できます。これにより、オブジェクトのパラメータを更新するだけで自動的にセッション内のデータも更新されるようになります。
次回以降はAWS ECSを使い、複数のコンテナ上でこのアプリケーションを実行します。異なるコンテナ上で実行されている複数のアプリケーションが共通して、同じセッションデータを保存しているElastiCacheにアクセスしていることがわかるように、リクエストのパスによって異なるコンテナへアクセスするよう、アプリケーションロードバランサーのパスベースルーティングを利用します。その際に画面から指定する「containerGroup」というパラメータで、アプリケーションロードバランサーが実行するコンテナを振り分けて指定できるように、セッションを保存するURLにはパスパターンにパラメータを含めておきましょう。
また、セッションを無効化する処理を持つメソッドも合わせて実装しておきます。
package org.debugroom.mynavi.sample.aws.elasticache.app.web;
import javax.servlet.http.HttpSession;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.debugroom.mynavi.sample.aws.elasticache.app.web.model.SampleSession;
@Controller
public class SampleController {
@Value("${app.host}")
private String host;
@Autowired
private SampleSession sampleSession;
@RequestMapping(method=RequestMethod.GET, value="/{containerGroup:[0-9]+}")
public String sharedSession(Model model){
sampleSession.setHost(host);
sampleSession.setLastUpdatedAt(new Date());
model.addAttribute("sampleSession", sampleSession);
return "sharedSession";
}
@RequestMapping(method=RequestMethod.GET, value="/invalidateSession")
public String invalidateSession(HttpSession session){
session.invalidate();
return "redirect:/index.html";
}
}
ホスト名は、ECSコンテナに設定された環境変数HOSTNAMEから取得できるように、application.ymlで下記のように設定しておきます。
app:
host: ${HOSTNAME:localhost}
これでアプリケーションが完成しました。SpringBoot起動クラスを実行し、アプリケーションを実行してみましょう。「http://localhost:8080/index.html」へブラウザからアクセスすると、以下のような画面が表示されます。
実行するコンテナの番号を入力し(ただし、ローカル環境では1つのAPしかないので意味はありません)、「Shared Session」ボタンを押下すると、Redisにセッション情報が追加されます。
「redis-cli」などを用いて、Redisのキー一覧を参照すると以下のように表示されるはずです。続けてhgetallコマンドでセッションに保存されたオブジェクトを表示させてみます。
127.0.0.1:6379> keys *
1) "spring:session:sessions:4e48e07b-bb62-46ea-8666-8fe8437d6d56"
2) "spring:session:sessions:expires:4e48e07b-bb62-46ea-8666-8fe8437d6d56"
3) "spring:session:expirations:1552045800000"
127.0.0.1:6379> hgetall "spring:session:sessions:4e48e07b-bb62-46ea-8666-8fe8437d6d56"
1) "lastAccessedTime"
2) "1552043971610"
3) "maxInactiveInterval"
4) "1800"
5) "creationTime"
6) "1552043970153"
7) "sessionAttr:scopedTarget.sampleSession"
8) "{\"@class\":\"org.debugroom.mynavi.sample.aws.elasticache.app.web.model.SampleSession\",\"host\":\"localhost\",\"lastUpdatedAt\":[\"java.util.Date\",1552043970167]}"
以上で、ローカル環境に構築したRedisにアクセスし、セッション情報を保存するアプリケーションを実装することができました。次回は、AWSでElastiCacheを構築してみます。
著者紹介
川畑 光平(KAWABATA Kohei) - NTTデータ 課長代理
金融機関システム業務アプリケーション開発・システム基盤担当を経て、現在はソフトウェア開発自動化関連の研究開発・推進に従事。
Red Hat Certified Engineer、Pivotal Certified Spring Professional、AWS Certified Solutions Architect Professional等の資格を持ち、アプリケーション基盤・クラウドなどさまざまな開発プロジェクト支援にも携わる。2019 APN AWS Top Engineers & Ambassadors選出。