PR

【Java】ResourceBundleキャッシュ問題の解決法: プロパティファイルのリアルタイム反映

Java

はじめに

Javaにおいてプロパティファイルの読み込みに使われるResourceBundleですが、プロパティファイルの変更がすぐに反映されない問題があります。原因と対応方法を見ていきましょう。

原因

ResourceBundleは、プロパティファイルの値を読み込むためのインスタンスの作成です。
インスタンス作成後、getBundleメソッドを使ってファイルを読み込むのですが、このgetBundleを実行した際に取得した結果がキャッシュに残されてしまいます。
そのため、次回getBundleが実行された際には、このキャッシュから値を取得しにいくので、プロパティファイルの値を変更しても、キャッシュの値は変更前のままのため、変更が反映されまないということが起こります。

システムの再起動を行うことでプロパティファイルを読み込み直すことができますが、常時稼働しているようなシステムの場合、そういうわけにはいきません。

再起動しなくても、プロパティファイルの値が反映されることはあります。
それは、ガベージコレクション(GC)が動いたときです。
このキャッシュが使われていない時に、GCが動くとそのキャッシュがクリアされるため、
GC後のgetBundle実行時には、プロパティファイルを読み込みに行くため、変更が反映されます。
しかし、GCによるキャッシュはいつ行われるかわからないため、即時変更したい場合には向いていません。

再起動やGCを待つことをなく常にプロパティファイルを変更する方法を紹介したいと思います。

対応方法

対応方法の案は2つあります。どちらもコード上での対応となります。
一つは明示的に、キャッシュクリアを実行する方法です。(clearCache )
もう一つは、キャッシュの有効期限値を設定し、その期限が過ぎると自動的にキャッシュがクリアされる方法です。(getTimeToLive )

案1 clearCache

一つ目の案はclearCacheの使用です。これはResourceBundleクラスに定義されているメソッドです。


単純に実行するだけで、キャッシュをクリアしてくれます。インスタンス作成の前に実行しておけば、getBundleは必ずファイルを読み込むようになりますので、プロパティファイルの変更が即座に反映されます。

使用例:

ResourceBundle.clearCache();
ResourceBundle rb = ResourceBundle.getBundle("sample");
String sample1 = rb.getString("sample1");

案2 getTimeToLive

2つ目の案はgetTimeToLiveの使用です。これはResourceBundle.Controlクラスに定義されているメソッドです。getTimeToLiveをオーバーライドし、有効期限を設定することが可能です。以下の使用例では、有効期限を10秒としています。設定されたcontrolをgetBundleの引数にすることで、この読み込みから10秒後にはキャッシュがクリアされます。

使用例:

ResourceBundle.Control control = new ResourceBundle.Control() {
    public long getTimeToLive(String baseName,Locale locale) {
        // リソースバンドルのキャッシュの有効期限は10秒
        return 10000L;
    }
};

ResourceBundle rb = ResourceBundle.getBundle("sample", Locale.getDefault(), control);
String sample1 = rb.getString("sample1");

また、ResourceBundle.Controlクラスには、2つの定数が用意されています。
上記例のreturn を 1000Lではなく、下記の定数に置き換えることができます。

TTL_DONT_CACHE:リソースバンドルはキャッシュされず、毎回ロードされます。
TTL_NO_EXPIRATION_CONTROL:キャッシュ期間が無期限となります。

以上が対応方法です。状況によっては、どちらの対応方法が適切かは異なるかもしれません。例えば、頻繁にプロパティファイルの値を変更する場合は、明示的にキャッシュをクリアする方法が有効です。
一方、値の変更がそれほど頻繁でない、または一定期間ごとにリフレッシュしたい場合は、有効期限を設定する方法が適しているかもしれません。

いずれの方法も、ResourceBundleの挙動を理解することで、より効率的なコードを書くことができると思います。どちらの方法が自分のプロジェクトに適しているかを理解し、適切に適用していきましょう。

さいごに

以上が今回のブログの内容となります。ResourceBundleのキャッシュ問題とその対応方法について、ご理解いただけたでしょうか。問題が発生した際には、このブログが皆様のお役に立てれば幸いです。

最後まで読んでいただき、ありがとうございました。

コメント

タイトルとURLをコピーしました