diff --git a/spring-context/src/main/java/org/springframework/context/support/ReloadableResourceBundleMessageSource.java b/spring-context/src/main/java/org/springframework/context/support/ReloadableResourceBundleMessageSource.java index ab45abf1b08..73de21f4b5c 100644 --- a/spring-context/src/main/java/org/springframework/context/support/ReloadableResourceBundleMessageSource.java +++ b/spring-context/src/main/java/org/springframework/context/support/ReloadableResourceBundleMessageSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,29 +50,20 @@ import org.springframework.util.StringUtils; * reloading files based on timestamp changes, but also of loading properties files * with a specific character encoding. It will detect XML property files as well. * - *
In contrast to {@link ResourceBundleMessageSource}, this class supports - * reloading of properties files through the {@link #setCacheSeconds "cacheSeconds"} - * setting, and also through programmatically clearing the properties cache. - * Since application servers typically cache all files loaded from the classpath, - * it is necessary to store resources somewhere else (for example, in the - * "WEB-INF" directory of a web app). Otherwise changes of files in the - * classpath will not be reflected in the application. - * - *
Note that the base names set as {@link #setBasenames "basenames"} property + *
Note that the basenames set as {@link #setBasenames "basenames"} property * are treated in a slightly different fashion than the "basenames" property of * {@link ResourceBundleMessageSource}. It follows the basic ResourceBundle rule of not * specifying file extension or language codes, but can refer to any Spring resource * location (instead of being restricted to classpath resources). With a "classpath:" * prefix, resources can still be loaded from the classpath, but "cacheSeconds" values - * other than "-1" (caching forever) will not work in this case. - * - *
This MessageSource implementation is usually slightly faster than - * {@link ResourceBundleMessageSource}, which builds on {@link java.util.ResourceBundle} - * - in the default mode, i.e. when caching forever. With "cacheSeconds" set to 1, - * message lookup takes about twice as long - with the benefit that changes in - * individual properties files are detected with a maximum delay of 1 second. - * Higher "cacheSeconds" values usually do not make a significant difference. + * other than "-1" (caching forever) might not work reliably in this case. * + *
For a typical web application, message files could be placed into {@code WEB-INF}: + * e.g. a "WEB-INF/messages" basename would fine a "WEB-INF/messages.properties", + * "WEB-INF/messages_en.properties" etc arrangement as well as "WEB-INF/messages.xml", + * "WEB-INF/messages_en.xml" etc. Note that message definitions in a previous + * resource bundle will override ones in a later bundle, due to sequential lookup. + *
This MessageSource can easily be used outside of an * {@link org.springframework.context.ApplicationContext}: It will use a * {@link org.springframework.core.io.DefaultResourceLoader} as default, @@ -244,6 +235,7 @@ public class ReloadableResourceBundleMessageSource extends AbstractMessageSource *
Default is "true": This behavior is new as of Spring Framework 4.1, * minimizing contention between threads. If you prefer the old behavior, * i.e. to fully block on refresh, switch this flag to "false". + * @since 4.1 * @see #setCacheSeconds */ public void setConcurrentRefresh(boolean concurrentRefresh) { diff --git a/spring-context/src/main/java/org/springframework/context/support/ResourceBundleMessageSource.java b/spring-context/src/main/java/org/springframework/context/support/ResourceBundleMessageSource.java index 23ae8340aaa..1f623674c5b 100644 --- a/spring-context/src/main/java/org/springframework/context/support/ResourceBundleMessageSource.java +++ b/spring-context/src/main/java/org/springframework/context/support/ResourceBundleMessageSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -51,11 +51,11 @@ import org.springframework.util.StringUtils; * base class. The caching provided by this MessageSource is significantly faster * than the built-in caching of the {@code java.util.ResourceBundle} class. * - *
Unfortunately, {@code java.util.ResourceBundle} caches loaded bundles - * forever: Reloading a bundle during VM execution is not possible. - * As this MessageSource relies on ResourceBundle, it faces the same limitation. - * Consider {@link ReloadableResourceBundleMessageSource} for an alternative - * that is capable of refreshing the underlying bundle files. + *
The basenames follow {@link java.util.ResourceBundle} conventions: essentially, + * a fully-qualified classpath location. If it doesn't contain a package qualifier + * (such as {@code org.mypackage}), it will be resolved from the classpath root. + * Note that the JDK's standard ResourceBundle treats dots as package separators: + * This means that "test.theme" is effectively equivalent to "test/theme". * * @author Rod Johnson * @author Juergen Hoeller @@ -404,8 +404,7 @@ public class ResourceBundleMessageSource extends AbstractMessageSource implement */ @Override public String toString() { - return getClass().getName() + ": basenames=[" + - StringUtils.arrayToCommaDelimitedString(this.basenames) + "]"; + return getClass().getName() + ": basenames=[" + StringUtils.arrayToCommaDelimitedString(this.basenames) + "]"; } diff --git a/spring-core/src/main/java/org/springframework/util/backoff/ExponentialBackOff.java b/spring-core/src/main/java/org/springframework/util/backoff/ExponentialBackOff.java index b3bfa9c65df..b7c6efd29cb 100644 --- a/spring-core/src/main/java/org/springframework/util/backoff/ExponentialBackOff.java +++ b/spring-core/src/main/java/org/springframework/util/backoff/ExponentialBackOff.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -103,6 +103,7 @@ public class ExponentialBackOff implements BackOff { this.multiplier = multiplier; } + /** * The initial interval in milliseconds. */ @@ -183,12 +184,12 @@ public class ExponentialBackOff implements BackOff { @Override public long nextBackOff() { - if (currentElapsedTime >= maxElapsedTime) { + if (this.currentElapsedTime >= maxElapsedTime) { return STOP; } long nextInterval = computeNextInterval(); - currentElapsedTime += nextInterval; + this.currentElapsedTime += nextInterval; return nextInterval; } @@ -205,7 +206,7 @@ public class ExponentialBackOff implements BackOff { else { this.currentInterval = multiplyInterval(maxInterval); } - return currentInterval; + return this.currentInterval; } private long multiplyInterval(long maxInterval) { @@ -217,9 +218,8 @@ public class ExponentialBackOff implements BackOff { @Override public String toString() { - String i = (this.currentInterval < 0 ? "n/a" : this.currentInterval + "ms"); - final StringBuilder sb = new StringBuilder("ExponentialBackOff{"); - sb.append("currentInterval=").append(i); + StringBuilder sb = new StringBuilder("ExponentialBackOff{"); + sb.append("currentInterval=").append(this.currentInterval < 0 ? "n/a" : this.currentInterval + "ms"); sb.append(", multiplier=").append(getMultiplier()); sb.append('}'); return sb.toString(); diff --git a/spring-core/src/main/java/org/springframework/util/backoff/FixedBackOff.java b/spring-core/src/main/java/org/springframework/util/backoff/FixedBackOff.java index 62566f701c6..55c23b5e8a0 100644 --- a/spring-core/src/main/java/org/springframework/util/backoff/FixedBackOff.java +++ b/spring-core/src/main/java/org/springframework/util/backoff/FixedBackOff.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -57,6 +57,7 @@ public class FixedBackOff implements BackOff { this.maxAttempts = maxAttempts; } + /** * Set the interval between two attempts in milliseconds. */ @@ -110,14 +111,13 @@ public class FixedBackOff implements BackOff { public String toString() { final StringBuilder sb = new StringBuilder("FixedBackOff{"); sb.append("interval=").append(FixedBackOff.this.interval); - String attemptValue = (FixedBackOff.this.maxAttempts == Long.MAX_VALUE ? "unlimited" - : String.valueOf(FixedBackOff.this.maxAttempts)); + String attemptValue = (FixedBackOff.this.maxAttempts == Long.MAX_VALUE ? + "unlimited" : String.valueOf(FixedBackOff.this.maxAttempts)); sb.append(", currentAttempts=").append(this.currentAttempts); sb.append(", maxAttempts=").append(attemptValue); sb.append('}'); return sb.toString(); } - } } diff --git a/spring-jms/src/main/java/org/springframework/jms/listener/DefaultMessageListenerContainer.java b/spring-jms/src/main/java/org/springframework/jms/listener/DefaultMessageListenerContainer.java index ba55ecc241e..c48c3439df7 100644 --- a/spring-jms/src/main/java/org/springframework/jms/listener/DefaultMessageListenerContainer.java +++ b/spring-jms/src/main/java/org/springframework/jms/listener/DefaultMessageListenerContainer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -175,7 +175,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe private Executor taskExecutor; - private BackOff backOff = createDefaultBackOff(DEFAULT_RECOVERY_INTERVAL); + private BackOff backOff = new FixedBackOff(DEFAULT_RECOVERY_INTERVAL, Long.MAX_VALUE); private int cacheLevel = CACHE_AUTO; @@ -229,6 +229,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe * attempt to recover. *
The {@link #setRecoveryInterval(long) recovery interval} is ignored * when this property is set. + * @since 4.1 */ public void setBackOff(BackOff backOff) { this.backOff = backOff; @@ -244,7 +245,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe * @see #handleListenerSetupFailure */ public void setRecoveryInterval(long recoveryInterval) { - this.backOff = createDefaultBackOff(recoveryInterval); + this.backOff = new FixedBackOff(recoveryInterval, Long.MAX_VALUE); } /** @@ -941,7 +942,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe StringBuilder msg = new StringBuilder(); msg.append("Stopping container for destination '") .append(getDestinationDescription()) - .append("' - back off policy does not allow ").append("for further attempts."); + .append("': back-off policy does not allow ").append("for further attempts."); logger.error(msg.toString()); stop(); } @@ -968,10 +969,11 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe } /** - * Apply the next back off time using the specified {@link BackOffExecution}. - *
Return {@code true} if the back off period has been applied and a new + * Apply the next back-off time using the specified {@link BackOffExecution}. + *
Return {@code true} if the back-off period has been applied and a new * attempt to recover should be made, {@code false} if no further attempt * should be made. + * @since 4.1 */ protected boolean applyBackOffTime(BackOffExecution execution) { long interval = execution.nextBackOff(); @@ -990,10 +992,6 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe return true; } - private FixedBackOff createDefaultBackOff(long interval) { - return new FixedBackOff(interval, Long.MAX_VALUE); - } - /** * Return whether this listener container is currently in a recovery attempt. *
May be used to detect recovery phases but also the end of a recovery phase, @@ -1205,7 +1203,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe } /** - * Apply the back off time once. In a regular scenario, the back off is only applied if we + * Apply the back-off time once. In a regular scenario, the back-off is only applied if we * failed to recover with the broker. This additional sleep period avoids a burst retry * scenario when the broker is actually up but something else if failing (i.e. listener * specific).