diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationProperties.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationProperties.java index 7c8c41e05ad3..8fadb6690971 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationProperties.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationProperties.java @@ -39,6 +39,7 @@ * values are externalized. * * @author Dave Syer + * @author Yanming Zhou * @since 1.0.0 * @see ConfigurationPropertiesScan * @see ConstructorBinding @@ -69,6 +70,14 @@ @AliasFor("value") String prefix() default ""; + /** + * The prefix of the properties that {@link #prefix()} will inherit, It's used for + * configuring multiple beans which share common properties. + * @return the prefix of the properties to inherit + * @see #prefix() + */ + String inheritedPrefix() default ""; + /** * Flag to indicate that when binding to this object invalid fields should be ignored. * Invalid means invalid according to the binder that is used, and usually this means diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java index 392a7804bf3f..b72da9a939de 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java @@ -128,6 +128,7 @@ * @author Stephane Nicoll * @author Madhura Bhave * @author Vladislav Kisel + * @author Yanming Zhou */ @ExtendWith(OutputCaptureExtension.class) class ConfigurationPropertiesTests { @@ -1270,6 +1271,25 @@ void loadWhenBindingToJavaBeanWithConversionToCustomListImplementation() { assertThat(this.context.getBean(SetterBoundCustomListProperties.class).getValues()).containsExactly("a", "b"); } + @Test + void loadWhenUsingInheritedPrefixForJavaBeanBinder() { + load(SetterBoundInheritedPrefixConfiguration.class, "spring.service.host=127.0.0.1", "spring.service.port=6379", + "additional.service.port=6380"); + SetterBoundServiceProperties properties = this.context.getBean("additionalServiceProperties", + SetterBoundServiceProperties.class); + assertThat(properties.getPort()).isEqualTo(6380); + assertThat(properties.getHost()).isEqualTo("127.0.0.1"); + } + + @Test + void loadWhenUsingInheritedPrefixForValueObjectBinder() { + load(ConstructorBoundInheritedPrefixConfiguration.class, "spring.service.host=127.0.0.1", + "spring.service.port=6379", "additional.service.port=6380"); + ConstructorBoundServiceProperties properties = this.context.getBean(ConstructorBoundServiceProperties.class); + assertThat(properties.getPort()).isEqualTo(6380); + assertThat(properties.getHost()).isEqualTo("127.0.0.1"); + } + private AnnotationConfigApplicationContext load(Class configuration, String... inlinedProperties) { return load(new Class[] { configuration }, inlinedProperties); } @@ -3310,4 +3330,68 @@ static final class CustomList extends ArrayList { } + @ConfigurationProperties(prefix = "spring.service") + static class SetterBoundServiceProperties { + + private String host = "localhost"; + + private int port = 6379; + + String getHost() { + return this.host; + } + + void setHost(String host) { + this.host = host; + } + + int getPort() { + return this.port; + } + + void setPort(int port) { + this.port = port; + } + + } + + @EnableConfigurationProperties(SetterBoundServiceProperties.class) + static class SetterBoundInheritedPrefixConfiguration { + + @Bean(autowireCandidate = false) // do not back off auto-configured one + @ConfigurationProperties(prefix = "additional.service", inheritedPrefix = "spring.service") + SetterBoundServiceProperties additionalServiceProperties() { + return new SetterBoundServiceProperties(); + } + + } + + @ConfigurationProperties(prefix = "additional.service", inheritedPrefix = "spring.service") + static class ConstructorBoundServiceProperties { + + private final String host; + + private final int port; + + public ConstructorBoundServiceProperties(@DefaultValue("localhost") String host, + @DefaultValue("6379") int port) { + this.host = host; + this.port = port; + } + + String getHost() { + return this.host; + } + + int getPort() { + return this.port; + } + + } + + @EnableConfigurationProperties(ConstructorBoundServiceProperties.class) + static class ConstructorBoundInheritedPrefixConfiguration { + + } + }