8
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SpringのMessageSourceをリロードする

Posted at

SpringのMessageSourceはプロパティファイルを読み取ってメッセージを取得することができます。
プロパティファイルを変更した場合、アプリケーションを再起動すればMessageSourceに反映されるのですが、アプリケーションを起動した状態で読み込むことができるのか調べてみました。

結論

  • ResourceBundleMessageSourceReloadableResourceBundleMessageSourceのどちらを利用しても再読込させることが可能
  • どちらのクラスもキャッシュの生存期間を指定でき、その期間超えた場合はファイルを再読込する
  • ただし、任意のタイミングで再読込したいならReloadableResourceBundleMessageSourceを使うべし

各MessageSourceについて

ResourceBundleMessageSource

JavaのResourceBundleを利用してプロパティファイルからメッセージを取得することができます。
キャッシュの生存期間を指定することができ、その期間を超えた場合はプロパティファイルを再度読み込みます。

ただし、手動でキャッシュを削除するようなメソッドは有していません。

ReloadableResourceBundleMessageSource

ResourceBundleという名前がついていますが、JavaのResourceBundleは利用しておらず、Spring側でメッセージ取得処理等を作り込んでいます。
こちらもキャッシュの生存期間を指定することができます。
また、キャッシュをクリアするメソッドがあるため、任意のタイミングでキャッシュを破棄できます。

なお、こちらのクラスではプロパティファイルだけでなく、XMLファイルを読み込むこともできます。

余談

Java5まではResourceBundleにキャッシュを制御する機能がなかったようです。
そのため、当時はReloadableResourceBundleMessageSourceでしか再読込できなかったようです。

検証

環境

  • Spring Boot 2.0.6.RELEASE (SpringFramework 5.0.10.RELEASE)
  • Java8

プロジェクトの準備

pom.xml(抜粋)
<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.0.6.RELEASE</version>
	<relativePath/>
</parent>

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
</dependencies>

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		</plugin>
	</plugins>
</build>

メッセージ定義ファイルの作成

プロパティファイルを作成します。

message.properties
hoge=hogehoge

再読込の確認をするために、これらのファイルはSpring Bootプロジェクトの外に配置します。
(私の場合は E:\test に格納しました。)

その他

MessageSourceをBean定義します。

@Bean
MessageSource resourceBundleMessageSource() {
    ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    messageSource.addBasenames("message");
    messageSource.setCacheSeconds(10);
    return messageSource;
}

@Bean
MessageSource reloadableResourceBundleMessageSource() {
    ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    messageSource.addBasenames("classpath:message");
    return messageSource;
}

ResourceBundleMessageSourceのキャッシュ生存期間は10秒に設定しました。
ReloadableResourceBundleMessageSourceは設定していないのでデフォルト値の-1となっており、常にキャッシュを利用します。
また、クラスパス上から取得する場合はbeasenameにclasspath:というprefixが必要です。

動作確認用のControllerは以下のような感じで。

@RestController
public class MessageController {

    @Autowired
    @Qualifier("resourceBundleMessageSource")
    MessageSource resourceBundleMessageSource;

    @Autowired
    @Qualifier("reloadableResourceBundleMessageSource")
    MessageSource reloadableResourceBundleMessageSource;

    @GetMapping("/")
    public Map<String, String> index() {
        Map<String, String> map = new HashMap<>();
        map.put("resouceBundleMessageSource:hoge",
                resourceBundleMessageSource.getMessage("hoge", null, Locale.getDefault()));
        map.put("reloadableResourceBundleMessageSource:hoge",
                reloadableResourceBundleMessageSource.getMessage("hoge", null, Locale.getDefault()));

        return map;
    }

    @GetMapping("/clear-cache")
    public Map<String, String> clearCache() {
        ((ReloadableResourceBundleMessageSource) reloadableResourceBundleMessageSource).clearCache();
        return index();
    }

}

動作確認

起動時にプロパティファイルを配置したディレクトリをクラスパスに追加する必要があります。
実はこのやり方を調べるのに一番時間がかかりました・・・。

Spring Boot Maven Pluginを利用する場合は以下のコマンドで実行すればOKです。

mvn spring-boot:run -Dspring-boot.run.folders="E:\test"

なお、起動引数ではなくpom.xmlに設定する場合は以下のような感じ。

pom.xml
<plugin>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-maven-plugin</artifactId>
	<configuration>
		<folders>
			<folder>E:\test</folder>
		</folders>
	</configuration>
</plugin>

Executable Jarの場合は・・・、話が逸れるのでそのうち別記事にしようと思います。

起動後、http://localhost:8080/ にアクセスすると、以下のように表示されます。

curl http://localhost:8080
{"reloadableResourceBundleMessageSource:hoge":"hogehoge","resouceBundleMessageSource:hoge":"hogehoge"}

アプリケーションは起動した状態でプロパティファイルを編集します。

message.properties
hoge=hogehoge!!!!

もう一度http://localhost:8080/ にアクセスすると、ResourceBundleMessageSourceはリロードされていることが確認できます。
(前回プロパティファイルを読み込んでから、cacheSecondsで設定した秒数が経過している必要があります。)

curl http://localhost:8080
{"reloadableResourceBundleMessageSource:hoge":"hogehoge","resouceBundleMessageSource:hoge":"hogehoge!!!!"}

つぎは、http://localhost:8080/clear-cache にアクセスすると、ReloadableResourceBundleMessageSourceもリロードされることを確認できます。

curl http://localhost:8080/clear-cache
{"reloadableResourceBundleMessageSource:hoge":"hogehoge!!!!","resouceBundleMessageSource:hoge":"hogehoge!!!!"}

以上のように、キャッシュの生存期間を指定してファイルを再読込したり、意図的にキャッシュを破棄して再読込させることができます。

8
8
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
8
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?