diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/MessageSourceAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/MessageSourceAutoConfiguration.java index ec87833c6f..b853baf73a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/MessageSourceAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/MessageSourceAutoConfiguration.java @@ -33,6 +33,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ConditionContext; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.AbstractResourceBasedMessageSource; +import org.springframework.context.support.ReloadableResourceBundleMessageSource; import org.springframework.context.support.ResourceBundleMessageSource; import org.springframework.core.Ordered; import org.springframework.core.io.Resource; @@ -65,7 +67,9 @@ public class MessageSourceAutoConfiguration { @Bean public MessageSource messageSource(MessageSourceProperties properties) { - ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); + AbstractResourceBasedMessageSource messageSource = (properties.isReloadable() + ? new ReloadableResourceBundleMessageSource() + : new ResourceBundleMessageSource()); if (StringUtils.hasText(properties.getBasename())) { messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray( StringUtils.trimAllWhitespace(properties.getBasename()))); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/MessageSourceProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/MessageSourceProperties.java index 62d366c2cd..b8985ea8ec 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/MessageSourceProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/MessageSourceProperties.java @@ -71,6 +71,12 @@ public class MessageSourceProperties { */ private boolean useCodeAsDefaultMessage = false; + /** + * Whether to use a "ReloadableResourceBundleMessageSource" rather than the default + * "ResourceBundleMessageSource". Recommended during development only. + */ + private boolean reloadable = false; + public String getBasename() { return this.basename; } @@ -119,4 +125,12 @@ public class MessageSourceProperties { this.useCodeAsDefaultMessage = useCodeAsDefaultMessage; } + public boolean isReloadable() { + return this.reloadable; + } + + public void setReloadable(boolean reloadable) { + this.reloadable = reloadable; + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/MessageSourceAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/MessageSourceAutoConfigurationTests.java index 7ea0371bfe..c31c222ae2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/MessageSourceAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/MessageSourceAutoConfigurationTests.java @@ -32,6 +32,9 @@ import org.springframework.context.NoSuchMessageException; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; +import org.springframework.context.support.DelegatingMessageSource; +import org.springframework.context.support.ReloadableResourceBundleMessageSource; +import org.springframework.context.support.ResourceBundleMessageSource; import static org.assertj.core.api.Assertions.assertThat; @@ -220,6 +223,38 @@ public class MessageSourceAutoConfigurationTests { .isEqualTo("bar"))); } + @Test + public void testDefaultReloadableValueMessageSource() { + testReloadableMessageSource(ResourceBundleMessageSource.class, + "spring.messages.basename:test/messages"); + } + + @Test + public void testNotReloadableMessageSource() { + testReloadableMessageSource(ResourceBundleMessageSource.class, + "spring.messages.basename:test/messages", + "spring.messages.reloadable:false"); + } + + @Test + public void testReloadableMessageSource() { + testReloadableMessageSource(ReloadableResourceBundleMessageSource.class, + "spring.messages.basename:test/messages", + "spring.messages.reloadable:true"); + } + + private void testReloadableMessageSource(Class expectedInstance, + String... propertyValues) { + this.contextRunner.withPropertyValues(propertyValues).run((context) -> { + MessageSource messageSource = context.getBean(MessageSource.class); + if (messageSource instanceof DelegatingMessageSource) { + messageSource = ((DelegatingMessageSource) messageSource) + .getParentMessageSource(); + } + assertThat(messageSource).isInstanceOf(expectedInstance); + }); + } + @Configuration @PropertySource("classpath:/switch-messages.properties") protected static class Config { diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index ede9ebeb73..4546300149 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -133,6 +133,7 @@ content into your application. Rather, pick only the properties that you need. spring.messages.cache-duration= # Loaded resource bundle files cache duration. When not set, bundles are cached forever. If a duration suffix is not specified, seconds will be used. spring.messages.encoding=UTF-8 # Message bundles encoding. spring.messages.fallback-to-system-locale=true # Whether to fall back to the system Locale if no files for a specific Locale have been found. + spring.messages.reloadable=false # Whether to use a ReloadableResourceBundleMessageSource instead of the default ResourceBundleMessageSource. Recommended during development only. spring.messages.use-code-as-default-message=false # Whether to use the message code as the default message instead of throwing a "NoSuchMessageException". Recommended during development only. # OUTPUT