1
3

More than 3 years have passed since last update.

【Java】Spring (Boot) で singleton service を使ってDBからデータを取得する

Last updated at Posted at 2020-09-30

Spring (Boot) で singleton service を使ってDBからデータを取得する

・enum にDI
・メモリの節約
・キャッシュ機能で高負荷に対応
・読み取りのみ
・ランキングなどで利用してます
・Spring Framework, Spring Boot 両対応
・マッパーの方は適宜読み替えて設定してください
・コンテキスト更新時に初期化
※参考:https://www.baeldung.com/spring-context-events

環境

・Spring Framework 4.2.9
・Spring Boot 2.2.1
・Java 1.8
・Windows 10 64bit

SampleRankingSingletonService

・データを取得し保持するシングルトンサービス (enum)
・mapper を @Autowired で DI したいけどできないので初期化用のサービスを別に作る
・データの加工はプログラムを追加して対応すると良いと思います。(SQLの発行は高負荷)

public enum SampleRankingSingletonService {

    INSTANCE;

    // 読み込みタイムアウト値調整
    public static final int TIMEOUT_SEC = 1800;

    private static final Object lock = new Object();

    private LocalDateTime queryDate;

    // 最新の ランキング
    private List<Sample> latestRanking = new CopyOnWriteArrayList<>();

    private SampleMapper sampleMapper;

    private SampleRankingSingletonService () {
    }

    public static SampleRankingSingletonService getInstance() {
        return INSTANCE;
    }

    private boolean isTimeout() {
        LocalDateTime execDate = LocalDateTime.now();
        if (queryDate == null) { return true; }

        LocalDateTime expireDate = queryDate.plusSeconds(TIMEOUT_SEC);
        if (expireDate.isBefore(execDate)) {
            return true;
        }
        return false;
    }

    public synchronized void reload() {
        queryDate = LocalDateTime.now();
        latestRanking = sampleMapper.selectLatestRanking(); // <- ランキング取得SQL発行
    }

    // データ処理を実行する前に呼び出す
    public void initQuery() {
        synchronized(lock) {
            if (isTimeout() || latestRanking.size() <= 0) {
                reload();
            }
        }
    }

    public Integer countLatestRanking() {
        return latestRanking.size();
    }
}

SampleRankingSingletonInitializerService

・DIにより自動生成

@Component
public class SampleRankingSingletonInitializerService {

    @Autowired
    private SampleMapper sampleMapper;

    // Bean生成時にシングルトンサービスにDIしたマッパーをセットする
    @PostConstruct
    public void init() {
        SampleRankingSingletonService.INSTANCE.setSampleMapper(sampleMapper);
    }

    // コンテキスト更新時に初回クエリ実行 (PostConstruct で実行すると Spring Boot ではエラーになる)       
    @EventListener
    public void onContextRefreshedEvent(ContextRefreshedEvent evt) {
        SampleRankingSingletonService.INSTANCE.initQuery();
    }

    public SampleMapper getSampleMapper() {
        return sampleMapper;
    }

    public void setSampleMapper(SampleMapper sampleMapper) {
        this.sampleMapper = sampleMapper;
    }
}

DI 用の xml ファイル

    <bean id="sample.sampleRankingSingletonInitializerService" class="org.sample.SampleRankingSingletonInitializerService">
        <property name="sampleMapper" ref="sample.SampleMapper" />
    </bean>

ブレイクポイント設定してサーバー起動後ちゃんと止まり、データが取れていればOKです。
以上、お疲れさまでした!

1
3
2

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
1
3