9
7

More than 1 year has passed since last update.

SpringのCache機能をサクッと利用する

Last updated at Posted at 2022-11-13

Spring(Spring Boot)のCache機能を使ってメソッドの呼び出し結果をキャッシュしておくサンプルです。

動作確認バージョン

  • Spring Boot 2.7.5
  • Spring Framework 5.3.23

Cache機能の有効化

@EnableCaching を付与するとSpring Bootさんの自動コンフィギュレーション機能によってSpringのCache機能が利用できるようになります。

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@EnableCaching // ★★★アノテーションを追加
public class SpringCacheDemoApplication {

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

}

キャッシュ対象のメソッドを指定

結果をキャッシュしたいメソッドに@Cacheableを付与する。下記のサンプルではキャッシュ名を「rates」にしています。

package com.example.demo;

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.security.SecureRandom;
import java.util.UUID;

@Component
public class RateRepository {

  @Cacheable("rates") // ★★★ キャッシュしたいメソッドにアノテーションを追加
  public Rate getRate(String unitId, String groupId, String type, String baseDate) {
    Rate rate = new Rate();
    rate.setId(UUID.randomUUID().toString());
    rate.setRate(BigDecimal.valueOf(new SecureRandom().nextLong()));
    return rate;
  }

}

動かしてみる

以下のJUnitを動かすと、同じパラメータでメソッドを呼び出した場合は、キャッシュ済みのインスタンスが返却されることがわかります。

@SpringBootTest
class SpringCacheDemoApplicationTests {

  @Autowired
  RateRepository rateRepository;

  @Test
  void contextLoads() {
    Rate rate1 = rateRepository.getRate("U001", "G001", "Credit", "20221114");
    Rate rate2 = rateRepository.getRate("U001", "G001", "Credit", "20221114");

    // ★★★ 同じインスタンスが返却される
    Assertions.assertThat(rate2.getId()).isEqualTo(rate1.getId());
    Assertions.assertThat(rate2.getRate()).isEqualTo(rate1.getRate());
    Assertions.assertThat(rate2).isSameAs(rate1);
  }

}

テストクラスでキャッシュを削除する

テストの場合は、他のテストに影響を与えないためにキャッシュ済みのデータをテスト毎に破棄しておいた方が良いので・・・テストクラスにCacheManagerをインジェクションしてキャッシュをクリアしておきます。

@SpringBootTest
class SpringCacheDemoApplicationTests {

  @Autowired
  RateRepository rateRepository;

  @Autowired
  CacheManager cacheManager;

  // ★★★ テスト実施前後にキャッシュをクリアする
  @BeforeEach
  @AfterEach
  void clearCache() {
    cacheManager.getCacheNames().stream()
        .map(cacheManager::getCache)
        .filter(Objects::nonNull)
        .forEach(Cache::clear);
  }

  @Test
  void contextLoads() {
    Rate rate1 = rateRepository.getRate("U001", "G001", "Credit", "20221114");
    Rate rate2 = rateRepository.getRate("U001", "G001", "Credit", "20221114");

    Assertions.assertThat(rate2.getId()).isEqualTo(rate1.getId());
    Assertions.assertThat(rate2.getRate()).isEqualTo(rate1.getRate());
    Assertions.assertThat(rate2).isSameAs(rate1);

    // ★★★ 明示的にキャッシュを削除してみる
    clearCache();

    // ★★★ キャッシュ削除後に同じパラメータでメソッドを呼び出しみる
    Rate rate3 = rateRepository.getRate("U001", "G001", "Credit", "20221114");

    // ★★★ Cacheクリア後は別のインスタンスが返却される
    Assertions.assertThat(rate3.getId()).isNotEqualTo(rate1.getId());
    Assertions.assertThat(rate3.getRate()).isNotEqualTo(rate1.getRate());
    Assertions.assertThat(rate3).isNotSameAs(rate1);
  }

}

参考ページ

9
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
7