SpringBoot+インメモリデータグリッド入門 (データ永続化)

# 前回やったこと
前回はSpringDataGeodeを使って、インメモリデータグリッドを使ったSpringBootアプリケーションを作成し、データがサーバに同期されたタイミングでイベント処理が行えるように実装を行いました。

[・SpringDataGeodeを使用したアプリケーション作成](https://qiita.com/soichiro0311/items/969d4ceadb5d818b3ecb)

[・SpringDataGeodeを使用したイベント処理実装](https://qiita.com/soichiro0311/items/1cad02f7e1320e246629)

# 今回やること
### インメモリデータグリッドのキャッシュに登録されたデータをディスクに永続化する

今回はSpringDataGeodeの機能を使い、インメモリキャッシュに登録されたデータをローカルのディスクに永続化し、更にキャッシュ組み込みアプリサーバの起動時に、永続化ファイルをロードしてキャッシュにデータを登録する実装をやります。

調べてみたところ、アノテーション一つ追加してやるだけで実現できそう。

- `SpringBootApplication`に以下のようにアノテーションを追加。

```java:ServerGeodeApplication.java
package spring.geode.server.geodeServer;

import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.Region;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.gemfire.ReplicatedRegionFactoryBean;
import org.springframework.data.gemfire.config.annotation.EnableDiskStore;
import org.springframework.data.gemfire.config.annotation.EnableDiskStore.DiskDirectory;
import org.springframework.data.gemfire.config.annotation.EnableLocator;
import org.springframework.data.gemfire.config.annotation.EnableManager;
import org.springframework.data.gemfire.config.annotation.PeerCacheApplication;
import org.springframework.data.gemfire.repository.config.EnableGemfireRepositories;

import spring.geode.geodeCommon.model.User;
import spring.geode.geodeCommon.region.UserRegion;
import spring.geode.server.geodeServer.repository.UserRepository;

@SpringBootApplication
@PeerCacheApplication(name = "SpringGeodeServerApplication", locators = "localhost[40404]")
@EnableGemfireRepositories(basePackageClasses = UserRepository.class)
// 今回追加したデータ永続化アノテーション
@EnableDiskStore(
		name="SimpleDiskStore",
		autoCompact=true,
		diskDirectories = @DiskDirectory(location="/hoge/fuga/SpringGeodeData")
		)
public class GeodeServerApplication {

	public static void main(String[] args) {
		SpringApplication.run(GeodeServerApplication.class, args);
	}

	@Configuration
	@EnableLocator(port = 40404)
	@EnableManager(start = true)
	static class LocatorManagerConfiguration {
	}

	@Configuration
	static class CacheInitializer {
		
		@Bean
	    Region<Integer, User> userRegion(final GemFireCache cache) {
			return new UserRegion().createUserRegion(cache);
	    }
		
		@Bean
	    public ReplicatedRegionFactoryBean<Integer, User> replicatedRegion(GemFireCache cache) {
			return new UserRegion().createUserRegionFactory(cache);
	    }
	}
}

```

`@EnableDiskStore`を有効にすることによって`diskDirectories`で指定した絶対パスの位置に永続化ファイルが吐き出される。

と、思いきや何故だかファイルが出力されず。。
アノテーションで解決する方法を模索しましたが、うまくいかず。。

仕方がないので、`Bean`に直接設定することにしました。。

```java:UserRegion.java
package spring.geode.geodeCommon.region;

import java.io.File;

import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.Region;
import org.springframework.data.gemfire.ReplicatedRegionFactoryBean;

import spring.geode.geodeCommon.listener.UserRegionListener;
import spring.geode.geodeCommon.model.User;

/**
 * ユーザを管理する{@link Region}の設定を作成する
 *
 */
public class UserRegion {
	/**
	 * {@link Region}の作成を行う
	 * @param cache
	 * @return
	 */
	public Region<Integer, User> createUserRegion(final GemFireCache cache) {
		return cache.<Integer, User>getRegion("Users");
	}

	/**
	 * {@link Region}に対する設定を行う
	 * @param cache
	 * @return
	 */
	public ReplicatedRegionFactoryBean<Integer, User> createUserRegionFactory(GemFireCache cache) {
		ReplicatedRegionFactoryBean<Integer, User> replicatedRegionFactory = new ReplicatedRegionFactoryBean<>();
		UserRegionListener[] listeners = { new UserRegionListener() };

		listeners[0] = new UserRegionListener();
		replicatedRegionFactory.setCacheListeners(listeners);
		replicatedRegionFactory.setClose(false);
		replicatedRegionFactory.setCache(cache);
		replicatedRegionFactory.setRegionName("Users");
		replicatedRegionFactory.setPersistent(true);
		return replicatedRegionFactory;
	}

	/**
	 * {@link Region}に対するファイル永続化設定を行う
	 * @param cache
	 * @param regionFactory
	 * @return
	 */
	public ReplicatedRegionFactoryBean<Integer, User> configDiskStore(GemFireCache cache,
			ReplicatedRegionFactoryBean<Integer, User> regionFactory) {
		File[] files = { new File("/hoge/fuga/SpringGeode/persistenceFile") };

		cache.createDiskStoreFactory()//
				.setAllowForceCompaction(true)//
				.setAutoCompact(true)//
				.setDiskDirs(files)//
				.create("SimpleDiskStore");

		regionFactory.setDiskStoreName("SimpleDiskStore");

		return regionFactory;
	}
}
```

`configDiskStore`メソッドで永続化設定を行っています。
`Cache`内に`DiskStore`を作成し、各種永続化方法に関する設定、永続化ファイルパスを設定しています。

[詳しくはここを参照](https://docs.spring.io/spring-gemfire/docs/current/api/org/springframework/data/gemfire/config/annotation/EnableDiskStore.html)


このメソッドをアプリケーション内で呼び出し、Bean登録してやることでやっと永続化が完了しました。

```java:GeodeServerApplication.java
package spring.geode.server.geodeServer;

import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.Region;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.gemfire.ReplicatedRegionFactoryBean;
import org.springframework.data.gemfire.config.annotation.EnableLocator;
import org.springframework.data.gemfire.config.annotation.EnableManager;
import org.springframework.data.gemfire.config.annotation.PeerCacheApplication;
import org.springframework.data.gemfire.repository.config.EnableGemfireRepositories;

import spring.geode.geodeCommon.model.User;
import spring.geode.geodeCommon.region.UserRegion;
import spring.geode.server.geodeServer.repository.UserRepository;

@SpringBootApplication
@PeerCacheApplication(name = "SpringGeodeServerApplication", locators = "localhost[40404]")
@EnableGemfireRepositories(basePackageClasses = UserRepository.class)
public class GeodeServerApplication {

	public static void main(String[] args) {
		SpringApplication.run(GeodeServerApplication.class, args);
	}

	@Configuration
	@EnableLocator(port = 40404)
	@EnableManager(start = true)
	static class LocatorManagerConfiguration {
	}

	@Configuration
	static class CacheInitializer {

		@Bean
		Region<Integer, User> userRegion(final GemFireCache cache) {
			return new UserRegion().createUserRegion(cache);
		}

		@Bean
		public ReplicatedRegionFactoryBean<Integer, User> replicatedRegion(GemFireCache cache) {
			UserRegion region = new UserRegion();
			return region.configDiskStore(cache, region.createUserRegionFactory(cache));
		}
	}
}

```

これで`Region`ごとに永続化設定を行うことができ、アプリ起動時には`DiskStore`に設定したファイルからデータをロードしてキャッシュに登録することができるようになりました。


アノテーションでサクッと実装したかったのですが、うまくいかなかったのが悔やまれる。。
`ReplicatedRegionFactoryBean`を自前でカスタムしているのがいけないのか。。

何はともあれ永続化はできたので良しとする。

RDBを永続化対象とした設定もできれば嬉しいけど、そのような機能を`SpringDataGeode`が提供してくれるという情報を得られなかったので、一旦ファイル永続化機能を使用して、永続化をやってみました。