エキサイト株式会社エンジニアの佐々木です。エキサイトホールディングス 2023 advent calendar 1日目を担当させていただきます。
今回は、SpringBoot/Javaで、サーバローカルなキャッシュをRedHatが開発しているInfinispanの組み込みモードを使用し実装していきます。
前提
## Java openjdk version "21.0.1" 2023-10-17 LTS OpenJDK Runtime Environment Corretto-21.0.1.12.1 (build 21.0.1+12-LTS) OpenJDK 64-Bit Server VM Corretto-21.0.1.12.1 (build 21.0.1+12-LTS, mixed mode, sharing)
## Gradle ------------------------------------------------------------ Gradle 8.4 ------------------------------------------------------------ Build time: 2023-10-04 20:52:13 UTC Revision: e9251e572c9bd1d01e503a0dfdf43aedaeecdc3f
## SpringBoot . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v3.2.0)
設定
build.gradleはこのように設定する。
dependencies { implementation 'org.springframework.boot:spring-boot-starter-cache' implementation 'org.springframework.boot:spring-boot-starter-web' developmentOnly 'org.springframework.boot:spring-boot-devtools' implementation 'org.infinispan:infinispan-spring-boot3-starter-embedded:14.0.13.Final' // SpringBoot3に対応したinfinispanの組み込みモードのライブラリ implementation 'org.infinispan:infinispan-component-annotations:10.1.8.Final' // infinispan共通で使用するライブラリ compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' }
SpringBootの設定用のコードは下記のように実装する。
@Configuration public class CacheConfig { /** * キャッシュの設定を行う. */ @Bean public EmbeddedCacheManager embeddedCacheManager(EmbeddedCacheManager embeddedCacheManager) { Arrays.stream(CacheType.values()).forEach(e -> { ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); org.infinispan.configuration.cache.Configuration configuration = configurationBuilder .expiration() .lifespan(e.getTtl(), TimeUnit.SECONDS) // キャッシュのTTLを設定する .build(); embeddedCacheManager.defineConfiguration(e.getName(), configuration); // 上記で設定した内容を CacheNameと共に、設定を行う } ); return embeddedCacheManager; } } enum CacheType { // キーごとにTTLを設定する用の enumを作成する MIN_1(CacheType.MIN_1_KEY, 60) // 1分のキャッシュ設定 , SECOND_30(CacheType.SECOND_30_KEY, 30); // 30秒のキャッシュ設定 public static final String MIN_1_KEY = "MIN_1"; public static final String SECOND_30_KEY = "SECOND_30"; @Getter private final String name; @Getter private final long ttl; CacheType(String name, long ttl) { this.name = name; this.ttl = ttl; } }
SpringBootのController/Serviceの実装は下記のようになる。
interface DemoService { Object get5SecondsExpirationData() throws InterruptedException; Object get10SecondsExpirationData() throws InterruptedException; } @RestController @RequestMapping("") @RequiredArgsConstructor public class DemoController { private final DemoService demoService; DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss"); @GetMapping("cacheExpiration5Seconds") public Object cacheExpiration5Seconds() throws InterruptedException { return LocalTime.now().format(formatter) + ":" + demoService.get5SecondsExpirationData(); } @GetMapping("cacheExpiration10Seconds") public Object cacheExpiration10Seconds() throws InterruptedException { return LocalTime.now().format(formatter) + ":" + demoService.get10SecondsExpirationData(); } } @Service class DemoServiceImpl implements DemoService { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss"); @Override @Cacheable(CacheType.SECOND_10_KEY) // 10秒キャッシュ指定 public Object get10SecondsExpirationData() throws InterruptedException { Thread.sleep(10000); // スリープ10秒 return "expiration 10 seconds \n"; } @Override @Cacheable(CacheType.SECOND_5_KEY) // 5秒キャッシュ指定 public Object get5SecondsExpirationData() throws InterruptedException { Thread.sleep(5000); // スリープ5秒 return "expiration 5 seconds \n"; } }
Service層のメソッドにアノテーションでそれぞれのキャッシュ時間を指定します。タイプセーフにキャッシュ指定できるようにしています。 検証用にService層内のメソッドが実行される場合は、それぞれ5秒、10秒待たされる実装になっています。
検証
5秒キャッシュの方のAPIを実行してみます。
キャッシュの有効期限が過ぎたタイミングで、5秒待たされるような挙動になっています。
まとめ
今回はInfinispanの組み込みモードを使用して、サーバーローカルなキャッシュ機構を作成してみました。SpringBootではこのようなライブラリを使用しなければ、HashMapを使用したキャッシュが作られますが、有効期限などの設定は自前で実装することになるので、これだけの設定で作れるは便利かと思います。サーバーローカルなキャッシュを設定とリモートサーバーキャッシュの両方を使用する設定は次回ブログに書きます。
最後に
エキサイトではフロントエンジニア、バックエンドエンジニア、アプリエンジニアを随時募集しております。長期インターンも歓迎していますので、興味があれば連絡いただければと思います。
募集職種一覧はこちらになります!(カジュアルからもOK) www.wantedly.com