Compare ResourceBundleMessageSource and ReloadableResourceBundleMessageSource. When would you choose one over the other?
answer
- ResourceBundle = classpath + permanent cache
- Reloadable = Spring Resource + cacheSeconds timer
- Reloadable reads file:/xml too
- Boot default = ResourceBundleMessageSource
- fallbackToSystemLocale gotcha on both
basics
~10 sResourceBundleMessageSource wraps java.util.ResourceBundle and caches bundles for the JVM's life. ReloadableResourceBundleMessageSource loads via Spring Resources and can re-read files on a timer (cacheSeconds), so you can change messages without a restart.
solid answer
~40 sBoth are AbstractMessageSource implementations. ResourceBundleMessageSource delegates to java.util.ResourceBundle, so it only reads from the classpath and caches bundles permanently (ResourceBundle's own cache) — you cannot reload without a JVM restart or clearing that cache. ReloadableResourceBundleMessageSource does its own file loading through Spring's Resource abstraction, so it can read from classpath:, file:, or any Resource location, and supports setCacheSeconds/setCacheMillis to periodically re-read changed .properties files at runtime — ideal for editing messages in dev or hot-updating in prod. It can also parse XML property files. Choose ResourceBundleMessageSource for simple, static, classpath-packaged messages (the Boot default); choose the Reloadable one when you need live reloading, non-classpath locations, or file-based ops-managed message files. Both use MessageFormat for argument substitution.
code
java · 9 lines@Bean
public MessageSource messageSource() {
var ms = new ReloadableResourceBundleMessageSource();
ms.setBasename("file:/etc/app/i18n/messages"); // outside the classpath
ms.setDefaultEncoding("UTF-8");
ms.setCacheSeconds(30); // re-check changed files every 30s
ms.setFallbackToSystemLocale(false); // fall back to messages.properties, not JVM locale
return ms;
}go deeper
Knows both load .properties files by basename.
Contrasts classpath+permanent-cache vs Resource-based reloading and picks appropriately.
Adds encoding, XML support, fallbackToSystemLocale, and reload-in-prod tradeoffs.
Weighs operational message management (external files, hot updates) vs immutable jar-packaged bundles across a fleet.
Both classes extend `AbstractMessageSource` and implement the same `MessageSource` contract; they differ in **how they load and cache** the underlying `.properties` files. **ResourceBundleMessageSource** - Delegates to the JDK's `java.util.ResourceBundle`. Basenames are resolved on the **classpath only** (via the class loader). - Inherits `ResourceBundle`'s **permanent caching**: once a bundle for a locale is loaded, it stays cached for the life of the class loader. There is no per-instance reload timer, so edited files are *not* picked up without a JVM restart (or a `ResourceBundle.clearCache()` call). - Uses `MessageFormat` for `{0}` substitution. Historically the JDK default encoding for property bundles was ISO-8859-1; set `defaultEncoding` (Spring Boot defaults it to UTF-8). - This is what **Spring Boot auto-configures** by default (`MessageSourceAutoConfiguration` → `ResourceBundleMessageSource` over the `messages` basename). **ReloadableResourceBundleMessageSource** - Loads files itself using Spring's `Resource` abstraction, so basenames may be `classpath:`, `file:`, `WEB-INF/…`, or any location — not just the classpath. - Supports **runtime reloading**: `setCacheSeconds(n)` (or `setCacheMillis`) re-checks file timestamps every n seconds and reloads changed files without a restart. `cacheSeconds = -1` (default) caches forever; `0` re-reads every access (dev only). - Can also read **XML** property files (`.properties` and `<properties>`-style XML). Honors `defaultEncoding` and `fileEncodings`. - Does **not** use `java.util.ResourceBundle`, so it sidesteps that permanent cache entirely. **Shared behavior / gotchas** - Both do locale fallback: `messages_fr_FR` → `messages_fr` → `messages`. - Both expose `fallbackToSystemLocale` (default `true`) — a classic gotcha: before falling back to the base file, they first try the *JVM's default* locale, so a server in a French locale may serve French to an English user whose file is missing. Set it `false` to fall straight to the base bundle. - Both support `alwaysUseMessageFormat`, `useCodeAsDefaultMessage`, and a parent `MessageSource`. **When to choose which** - **ResourceBundleMessageSource**: static messages packaged in the jar, simplest setup, no reload need — the sensible default. - **ReloadableResourceBundleMessageSource**: you need hot-editing during development, ops-managed external message files, non-classpath locations, or XML message files.
- Why can't ResourceBundleMessageSource reload edited files at runtime?It delegates to java.util.ResourceBundle, which caches loaded bundles permanently per class loader. Without clearing that cache (or restarting), edits are never re-read; ReloadableResourceBundleMessageSource avoids this by loading files itself with a timestamp-based cache timer.
- What does fallbackToSystemLocale=true do and why is it a gotcha?If a locale-specific file is missing, it first tries the JVM's default locale before the base file. On a server whose default locale isn't English, users can silently get the wrong language; setting it false falls back directly to the base bundle.
saying these in an interview costs you the question
- Claiming ReloadableResourceBundleMessageSource uses java.util.ResourceBundle (it does not)
- Saying ResourceBundleMessageSource can read from file: paths (classpath only)
- Believing cacheSeconds exists on ResourceBundleMessageSource