前に、Infinispan 9から入ったSpring Sessionのサポート(Embedded Mode)を試しました。
InfinispanのSpring Session Support(Embedded)を試す - CLOVER
今度は、Remote(Hot Rod)で試してみたいと思います。
Externalizing session using Spring Session
どういうものかというと、Spring Sessionでのデータの保存先を、Infinispan Server(Hot Rod)にできるという
話ですね。
プログラムを作るにあたり、前回同様、今回もSpring Boot向けのモジュールを使用します。
Using Infinispan with Spring Boot
GitHub - infinispan/infinispan-spring-boot: Infinispan Spring Boot
Infinispan: Spring Boot Starters
準備
作成したpom.xmlは、このような感じで。
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.littlewings</groupId> <artifactId>remote-spring-session</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <scala-maven-plugin.version>3.2.2</scala-maven-plugin.version> <scala.version>2.12.2</scala.version> <infinispan.version>9.0.3.Final</infinispan.version> <infinispan-spring-boot.version>1.0.0.Final</infinispan-spring-boot.version> <spring-boot.version>1.5.4.RELEASE</spring-boot.version> <spring-session.version>1.3.1.RELEASE</spring-session.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.infinispan</groupId> <artifactId>infinispan-bom</artifactId> <version>${infinispan.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.infinispan</groupId> <artifactId>infinispan-spring-boot-starter</artifactId> <version>${infinispan-spring-boot.version}</version> </dependency> <dependency> <groupId>org.infinispan</groupId> <artifactId>infinispan-spring4-remote</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session</artifactId> <version>${spring-session.version}</version> </dependency> <dependency> <groupId>org.scala-lang</groupId> <artifactId>scala-library</artifactId> <version>${scala.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>net.alchim31.maven</groupId> <artifactId>scala-maven-plugin</artifactId> <version>${scala-maven-plugin.version}</version> <executions> <execution> <goals> <goal>compile</goal> <goal>testCompile</goal> </goals> </execution> </executions> <configuration> <scalaVersion>${scala.version}</scalaVersion> <args> <arg>-Xlint</arg> <arg>-unchecked</arg> <arg>-deprecation</arg> <arg>-feature</arg> </args> <recompileMode>incremental</recompileMode> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring-boot.version}</version> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
主要なライブラリのバージョンは、BOMで指定。今回はInfinispanのものを優先したいので、こちらを先に書いておきます。
<dependencyManagement> <dependencies> <dependency> <groupId>org.infinispan</groupId> <artifactId>infinispan-bom</artifactId> <version>${infinispan.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
InfinispanのSpring Boot用のモジュール、Spring 4向けのRemote(Hot Rod)用モジュールを加えます。
<dependency> <groupId>org.infinispan</groupId> <artifactId>infinispan-spring-boot-starter</artifactId> <version>${infinispan-spring-boot.version}</version> </dependency> <dependency> <groupId>org.infinispan</groupId> <artifactId>infinispan-spring4-remote</artifactId> </dependency>
最後に、Spring BootのWeb用のStarterとSpring Sessionを追加。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session</artifactId> <version>${spring-session.version}</version> </dependency>
依存関係については、このくらいですね。
Infinispan Serverについては1 Nodeで起動済みとしますが、InfinispanのSpring Session向けのモジュールでは、セッション用のCacheとして
デフォルトで「sessions」という名前のCacheを利用するので、こちらを先に作成しておきます。
Infinispan Serverの管理ユーザーの作成。今回は「ispn-admin / ispn-password」とします。
$ bin/add-user.sh -u ispn-admin -p ispn-password Added user 'ispn-admin' to file '/path/to/standalone/configuration/mgmt-users.properties' Added user 'ispn-admin' to file '/path/to/domain/configuration/mgmt-users.properties'
Distributed Cacheの作成。
$ bin/ispn-cli.sh -c -u=ispn-admin -p=ispn-password [standalone@localhost:9990 /] /subsystem=datagrid-infinispan/cache-container=clustered/configurations=CONFIGURATIONS/distributed-cache-configuration=sessions-configuration:add(start=EAGER,mode=SYNC) {"outcome" => "success"} [standalone@localhost:9990 /] /subsystem=datagrid-infinispan/cache-container=clustered/distributed-cache=sessions:add(configuration=sessions-configuration) {"outcome" => "success"}
これで、準備はおしまいです。
サンプルコードの作成
サンプルコード自体は、Embedded Modeとほぼ同じものを使います。
src/main/scala/org/littlewings/infinispan/spring/App.scala
package org.littlewings.infinispan.spring import org.infinispan.spring.session.configuration.EnableInfinispanRemoteHttpSession import org.springframework.boot.SpringApplication import org.springframework.boot.autoconfigure.SpringBootApplication object App { def main(args: Array[String]): Unit = { SpringApplication.run(classOf[App], args: _*) } } @EnableInfinispanRemoteHttpSession @SpringBootApplication class App
ポイントは、@EnableInfinispanRemoteHttpSessionアノテーションを付与しておくことです。@EnableInfinispanRemoteHttpSessionアノテーションでは、
Spring Sessionで使うInfinispanのCache名とセッションの有効期限を設定することができます。
デフォルトでは、Cacheの名前が「sessions」で、有効期限が30分です。
https://github.com/infinispan/infinispan/blob/9.0.3.Final/spring/spring4/spring4-remote/src/main/java/org/infinispan/spring/session/configuration/EnableInfinispanRemoteHttpSession.java
今回は、デフォルトのまま使用します。
あとは、RestControllerとセッション間で共有するBeanを作成します。
src/main/scala/org/littlewings/infinispan/spring/CounterController.scala
package org.littlewings.infinispan.spring import java.time.LocalDateTime import java.time.format.DateTimeFormatter import org.springframework.stereotype.Component import org.springframework.web.bind.annotation.{GetMapping, RestController} import org.springframework.web.context.annotation.SessionScope import scala.collection.JavaConverters._ @RestController class CounterController(counter: Counter) { @GetMapping(Array("counter/access")) def access: java.util.Map[String, AnyRef] = { counter.increment() Map[String, AnyRef]( "value" -> Integer.valueOf(counter.value), "time" -> counter.time.format(DateTimeFormatter.ISO_DATE_TIME) ).asJava } } @SessionScope @Component @SerialVersionUID(1L) class Counter extends Serializable { var value: Int = 0 val time: LocalDateTime = LocalDateTime.now def increment(): Unit = value += 1 }
設定ファイルについては、このように。
src/main/resources/hotrod-client.properties
infinispan.client.hotrod.server_list=172.17.0.2:11222
これは、InfinispanのHot Rod Clientが読み込む設定ファイルです。「hotrod-client.properties」ファイルを用意しない場合は、
Spring Bootのapplication.propertiesに設定を書きます。
src/main/resources/application.properties
## hotrod-client.properties を使わない場合はこちらでも可(ファイルがない場合に、このプロパティが参照される) infinispan.remote.server-list=172.17.0.2:11222
コメントにも似たようなことを書いていますが、「hotrod-client.properties」ファイルを用意した場合は、application.propertiesに書いた
設定は無視されます。
なお、hotrod-client.propertiesに設定できる項目、キーは、こちらを参照するとよいです。
https://github.com/infinispan/infinispan/blob/9.0.3.Final/client/hotrod-client/src/main/java/org/infinispan/client/hotrod/impl/ConfigurationProperties.java
これで、準備はおしまいです。
確認
では、パッケージングして確認してみます。
$ mvn package
アプリケーションは、2つ起動させましょう。
# No.1 $ java -jar target/remote-spring-session-0.0.1-SNAPSHOT.jar # No.2 $ java -jar target/remote-spring-session-0.0.1-SNAPSHOT.jar --server.port=9080
curlで各アプリケーションにアクセスして確認します。
## アプリケーション1 $ curl -c cookie.txt -b cookie.txt -i http://localhost:8080/counter/access HTTP/1.1 200 Set-Cookie: SESSION=32ebed0d-d477-4352-b2ab-e31163a2ebfb; Path=/; HttpOnly Content-Type: application/json;charset=UTF-8 Transfer-Encoding: chunked Date: Fri, 07 Jul 2017 14:36:03 GMT {"value":1,"time":"2017-07-07T23:36:00.944"} ## アプリケーション2 $ curl -c cookie.txt -b cookie.txt -i http://localhost:9080/counter/access HTTP/1.1 200 Content-Type: application/json;charset=UTF-8 Transfer-Encoding: chunked Date: Fri, 07 Jul 2017 14:36:21 GMT {"value":2,"time":"2017-07-07T23:36:00.944"} ## アプリケーション1 $ curl -c cookie.txt -b cookie.txt -i http://localhost:908080/counter/access HTTP/1.1 200 Content-Type: application/json;charset=UTF-8 Transfer-Encoding: chunked Date: Fri, 07 Jul 2017 14:36:56 GMT {"value":3,"time":"2017-07-07T23:36:00.944"} ## アプリケーション2 $ curl -c cookie.txt -b cookie.txt -i http://localhost:809080/counter/access HTTP/1.1 200 Content-Type: application/json;charset=UTF-8 Transfer-Encoding: chunked Date: Fri, 07 Jul 2017 14:37:23 GMT {"value":4,"time":"2017-07-07T23:36:00.944"} ## アプリケーション1 $ curl -c cookie.txt -b cookie.txt -i http://localhost:908080/counter/access HTTP/1.1 200 Content-Type: application/json;charset=UTF-8 Transfer-Encoding: chunked Date: Fri, 07 Jul 2017 14:37:32 GMT {"value":5,"time":"2017-07-07T23:36:00.944"} ## アプリケーション2 $ curl -c cookie.txt -b cookie.txt -i http://localhost:809080/counter/access HTTP/1.1 200 Content-Type: application/json;charset=UTF-8 Transfer-Encoding: chunked Date: Fri, 07 Jul 2017 14:37:41 GMT {"value":6,"time":"2017-07-07T23:36:00.944"}
Bean作成時に生成された時間も変わっていませんし、インクリメントした値も共有されてそうなのでOKですね。
まとめ
InfinispanのSpring Session向けのモジュールを、今回はHot Rod Clientで、かつSpring Boot向けのStarterと一緒に使ってみました。
Infinispan ServerにつなぐところとInfinispanのSpring Session有効化のアノテーションが違うくらいで、さらっと使えて
いいですね。
今回作成したコードは、こちらに置いています。
https://github.com/kazuhira-r/infinispan-getting-started/tree/master/remote-spring-session