3333import java .util .PropertyResourceBundle ;
3434import java .util .ResourceBundle ;
3535import java .util .Set ;
36+ import java .util .concurrent .ConcurrentHashMap ;
3637
3738import org .springframework .beans .factory .BeanClassLoaderAware ;
3839import org .springframework .lang .Nullable ;
@@ -80,7 +81,7 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
8081 * This allows for very efficient hash lookups, significantly faster
8182 * than the ResourceBundle class's own cache.
8283 */
83- private final Map <String , Map <Locale , ResourceBundle >> cachedResourceBundles = new HashMap <>();
84+ private final Map <String , Map <Locale , ResourceBundle >> cachedResourceBundles = new ConcurrentHashMap <>();
8485
8586 /**
8687 * Cache to hold already generated MessageFormats.
@@ -90,7 +91,7 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
9091 * very efficient hash lookups without concatenated keys.
9192 * @see #getMessageFormat
9293 */
93- private final Map <ResourceBundle , Map <String , Map <Locale , MessageFormat >>> cachedBundleMessageFormats = new HashMap <>();
94+ private final Map <ResourceBundle , Map <String , Map <Locale , MessageFormat >>> cachedBundleMessageFormats = new ConcurrentHashMap <>();
9495
9596
9697 /**
@@ -178,31 +179,32 @@ protected ResourceBundle getResourceBundle(String basename, Locale locale) {
178179 }
179180 else {
180181 // Cache forever: prefer locale cache over repeated getBundle calls.
181- synchronized (this .cachedResourceBundles ) {
182- Map <Locale , ResourceBundle > localeMap = this .cachedResourceBundles .get (basename );
183- if (localeMap != null ) {
184- ResourceBundle bundle = localeMap .get (locale );
185- if (bundle != null ) {
186- return bundle ;
187- }
188- }
189- try {
190- ResourceBundle bundle = doGetBundle (basename , locale );
191- if (localeMap == null ) {
192- localeMap = new HashMap <>();
193- this .cachedResourceBundles .put (basename , localeMap );
194- }
195- localeMap .put (locale , bundle );
182+ Map <Locale , ResourceBundle > localeMap = this .cachedResourceBundles .get (basename );
183+ if (localeMap != null ) {
184+ ResourceBundle bundle = localeMap .get (locale );
185+ if (bundle != null ) {
196186 return bundle ;
197187 }
198- catch (MissingResourceException ex ) {
199- if (logger .isWarnEnabled ()) {
200- logger .warn ("ResourceBundle [" + basename + "] not found for MessageSource: " + ex .getMessage ());
188+ }
189+ try {
190+ ResourceBundle bundle = doGetBundle (basename , locale );
191+ if (localeMap == null ) {
192+ localeMap = new ConcurrentHashMap <>();
193+ Map <Locale , ResourceBundle > existing = this .cachedResourceBundles .putIfAbsent (basename , localeMap );
194+ if (existing != null ) {
195+ localeMap = existing ;
201196 }
202- // Assume bundle not found
203- // -> do NOT throw the exception to allow for checking parent message source.
204- return null ;
205197 }
198+ localeMap .put (locale , bundle );
199+ return bundle ;
200+ }
201+ catch (MissingResourceException ex ) {
202+ if (logger .isWarnEnabled ()) {
203+ logger .warn ("ResourceBundle [" + basename + "] not found for MessageSource: " + ex .getMessage ());
204+ }
205+ // Assume bundle not found
206+ // -> do NOT throw the exception to allow for checking parent message source.
207+ return null ;
206208 }
207209 }
208210 }
@@ -249,36 +251,40 @@ protected ResourceBundle loadBundle(Reader reader) throws IOException {
249251 protected MessageFormat getMessageFormat (ResourceBundle bundle , String code , Locale locale )
250252 throws MissingResourceException {
251253
252- synchronized (this .cachedBundleMessageFormats ) {
253- Map <String , Map <Locale , MessageFormat >> codeMap = this .cachedBundleMessageFormats .get (bundle );
254- Map <Locale , MessageFormat > localeMap = null ;
255- if (codeMap != null ) {
256- localeMap = codeMap .get (code );
257- if (localeMap != null ) {
258- MessageFormat result = localeMap .get (locale );
259- if (result != null ) {
260- return result ;
261- }
254+ Map <String , Map <Locale , MessageFormat >> codeMap = this .cachedBundleMessageFormats .get (bundle );
255+ Map <Locale , MessageFormat > localeMap = null ;
256+ if (codeMap != null ) {
257+ localeMap = codeMap .get (code );
258+ if (localeMap != null ) {
259+ MessageFormat result = localeMap .get (locale );
260+ if (result != null ) {
261+ return result ;
262262 }
263263 }
264+ }
264265
265- String msg = getStringOrNull (bundle , code );
266- if (msg != null ) {
267- if (codeMap == null ) {
268- codeMap = new HashMap <>();
269- this .cachedBundleMessageFormats .put (bundle , codeMap );
266+ String msg = getStringOrNull (bundle , code );
267+ if (msg != null ) {
268+ if (codeMap == null ) {
269+ codeMap = new ConcurrentHashMap <>();
270+ Map <String , Map <Locale , MessageFormat >> existing = this .cachedBundleMessageFormats .putIfAbsent (bundle , codeMap );
271+ if (existing != null ) {
272+ codeMap = existing ;
270273 }
271- if (localeMap == null ) {
272- localeMap = new HashMap <>();
273- codeMap .put (code , localeMap );
274+ }
275+ if (localeMap == null ) {
276+ localeMap = new ConcurrentHashMap <>();
277+ Map <Locale , MessageFormat > existing = codeMap .putIfAbsent (code , localeMap );
278+ if (existing != null ) {
279+ localeMap = existing ;
274280 }
275- MessageFormat result = createMessageFormat (msg , locale );
276- localeMap .put (locale , result );
277- return result ;
278281 }
279-
280- return null ;
282+ MessageFormat result = createMessageFormat (msg , locale );
283+ localeMap .put (locale , result );
284+ return result ;
281285 }
286+
287+ return null ;
282288 }
283289
284290 /**
0 commit comments