概要
今回はSpring Bootでメッセージファイル(.properties)を分割する方法を紹介します。
application.propertiesでspring.messages.basenameをカンマ区切りで指定すれば複数ファイルに分割が可能ですが、ファイル数が多くなってくると管理が大変なので、特定のフォルダにあるメッセージファイルを動的に読み込めるようにしました。
1. MessageSourceAutoConfigurationを起動させないようにする
Spring Bootはデフォルトでspring.messages.basenameに指定された場所にメッセージファイルがあれば、MessageSourceAutoConfigurationクラスを実行し、MessageSourceのBeanを生成します。
今回は自前でMessageSourceを生成したいので、spring.messages.basenameのデフォルト値である、resources/messages.propertiesを配置しないようにします。
2. Configクラス
Configクラスを下記の内容で作成します。
Kotlinで書いていますが、Javaでも同様です。
このサンプルではresources/i18n内のメッセージファイルを読み込みます。
処理的にちょっと強引な感じですが。。。
package ...
import org.springframework.context.MessageSource
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.support.ResourceBundleMessageSource
import org.springframework.core.io.support.ResourcePatternResolver
import org.springframework.util.StringUtils
import java.nio.charset.StandardCharsets
@Configuration
class AppConfig {
/**
* メッセージソースを生成します
*/
@Bean
fun messageSource(resourcePatternResolver : ResourcePatternResolver): MessageSource {
val messageSource = ResourceBundleMessageSource()
// エンコーディングのセット(必要に応じて)
messageSource.setDefaultEncoding(StandardCharsets.UTF_8)
// その他の設定
/*
messageSource.setFallbackToSystemLocale(xxx)
messageSource.setCacheMillis(xxx)
messageSource.setAlwaysUseMessageFormat(xxx)
messageSource.setUseCodeAsDefaultMessage(xxx)
*/
// 動的メッセージの取得
// パターン指定でプロパティファイルの一覧を取得
resourcePatternResolver.getResources("classpath*:i18n/*.properties")
.filter { it.isFile }.mapNotNull { it.filename }.forEach {
val baseName = if (it.contains("_")) { // ロケールあり(ファイル名に"_"が含まれている)
it.substringBeforeLast("_")
} else { // ロケールなし
it.removeSuffix(".properties")
}
messageSource.addBasenames("i18n/$baseName")
}
}
return messageSource
}
以上です。
まとめ
ちょっと強引な処理ですが、参考になれば幸いです。
また、ファイルの分割数が多い場合のパフォーマンス低下が気になり、500個以上のファイルを作成してメッセージの取得時間の計測を行いました。
最初の1回目のアクセスだけメッセージファイルの件数に比例してメッセージの取得時間が伸びましたが、2回目以降(別のメッセージキーでも可)は高速でメッセージが取得できました。
内部処理を追えていませんが、キャッシュか先読みっぽい処理が入っているのでは無いかと思います。