Skip to content

Commit 11c143b

Browse files
committed
1 parent fa686bb commit 11c143b

File tree

3 files changed

+121
-4
lines changed

3 files changed

+121
-4
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanRegistrar.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,19 @@
1616

1717
package org.springframework.boot.context.properties;
1818

19+
import org.springframework.aop.scope.ScopedProxyUtils;
1920
import org.springframework.beans.factory.BeanFactory;
2021
import org.springframework.beans.factory.ListableBeanFactory;
21-
import org.springframework.beans.factory.config.BeanDefinition;
22+
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
23+
import org.springframework.beans.factory.config.BeanDefinitionHolder;
24+
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
2225
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
2326
import org.springframework.beans.factory.support.RootBeanDefinition;
2427
import org.springframework.boot.context.properties.bind.BindMethod;
28+
import org.springframework.context.annotation.AnnotationScopeMetadataResolver;
29+
import org.springframework.context.annotation.ScopeMetadata;
30+
import org.springframework.context.annotation.ScopeMetadataResolver;
31+
import org.springframework.context.annotation.ScopedProxyMode;
2532
import org.springframework.core.annotation.MergedAnnotation;
2633
import org.springframework.core.annotation.MergedAnnotations;
2734
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
@@ -38,6 +45,8 @@
3845
*/
3946
final class ConfigurationPropertiesBeanRegistrar {
4047

48+
private static final ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
49+
4150
private final BeanDefinitionRegistry registry;
4251

4352
private final BeanFactory beanFactory;
@@ -75,17 +84,25 @@ private void registerBeanDefinition(String beanName, Class<?> type,
7584
MergedAnnotation<ConfigurationProperties> annotation) {
7685
Assert.state(annotation.isPresent(), () -> "No " + ConfigurationProperties.class.getSimpleName()
7786
+ " annotation found on '" + type.getName() + "'.");
78-
this.registry.registerBeanDefinition(beanName, createBeanDefinition(beanName, type));
87+
BeanDefinitionReaderUtils.registerBeanDefinition(createBeanDefinition(beanName, type), this.registry);
7988
}
8089

81-
private BeanDefinition createBeanDefinition(String beanName, Class<?> type) {
90+
private BeanDefinitionHolder createBeanDefinition(String beanName, Class<?> type) {
8291
BindMethod bindMethod = ConfigurationPropertiesBean.deduceBindMethod(type);
8392
RootBeanDefinition definition = new RootBeanDefinition(type);
8493
BindMethodAttribute.set(definition, bindMethod);
8594
if (bindMethod == BindMethod.VALUE_OBJECT) {
8695
definition.setInstanceSupplier(() -> ConstructorBound.from(this.beanFactory, beanName, type));
8796
}
88-
return definition;
97+
ScopeMetadata metadata = scopeMetadataResolver.resolveScopeMetadata(new AnnotatedGenericBeanDefinition(type));
98+
definition.setScope(metadata.getScopeName());
99+
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(definition, beanName);
100+
ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
101+
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
102+
return definitionHolder;
103+
}
104+
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
105+
return ScopedProxyUtils.createScopedProxy(definitionHolder, this.registry, proxyTargetClass);
89106
}
90107

91108
}

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanRegistrarTests.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,15 @@
2020

2121
import org.junit.jupiter.api.Test;
2222

23+
import org.springframework.aop.scope.ScopedProxyFactoryBean;
2324
import org.springframework.beans.factory.config.BeanDefinition;
2425
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
2526
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
2627
import org.springframework.beans.factory.support.GenericBeanDefinition;
2728
import org.springframework.beans.factory.support.RootBeanDefinition;
2829
import org.springframework.boot.context.properties.bind.BindMethod;
30+
import org.springframework.context.annotation.Scope;
31+
import org.springframework.context.annotation.ScopedProxyMode;
2932

3033
import static org.assertj.core.api.Assertions.assertThat;
3134
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
@@ -44,12 +47,38 @@ class ConfigurationPropertiesBeanRegistrarTests {
4447
private final ConfigurationPropertiesBeanRegistrar registrar = new ConfigurationPropertiesBeanRegistrar(
4548
this.registry);
4649

50+
@Test
51+
void registerScopedBeanDefinition() {
52+
String beanName = "scopedbeancp-" + ScopedBeanConfigurationProperties.class.getName();
53+
this.registrar.register(ScopedBeanConfigurationProperties.class);
54+
BeanDefinition beanDefinition = this.registry.getBeanDefinition(beanName);
55+
assertThat(beanDefinition).isNotNull();
56+
assertThat(beanDefinition.getBeanClassName()).isEqualTo(ScopedBeanConfigurationProperties.class.getName());
57+
assertThat(beanDefinition.getScope()).isEqualTo(BeanDefinition.SCOPE_PROTOTYPE);
58+
}
59+
60+
@Test
61+
void registerScopedBeanDefinitionWithProxyMode() {
62+
String beanName = "scopedbeancp-" + ProxyScopedBeanConfigurationProperties.class.getName();
63+
this.registrar.register(ProxyScopedBeanConfigurationProperties.class);
64+
BeanDefinition proxiedBeanDefinition = this.registry.getBeanDefinition(beanName);
65+
assertThat(proxiedBeanDefinition).isNotNull();
66+
assertThat(proxiedBeanDefinition.getBeanClassName()).isEqualTo(ScopedProxyFactoryBean.class.getName());
67+
String targetBeanName = (String) proxiedBeanDefinition.getPropertyValues().get("targetBeanName");
68+
assertThat(targetBeanName).isNotNull();
69+
BeanDefinition beanDefinition = this.registry.getBeanDefinition(targetBeanName);
70+
assertThat(beanDefinition).isNotNull();
71+
assertThat(beanDefinition.getBeanClassName()).isEqualTo(ProxyScopedBeanConfigurationProperties.class.getName());
72+
assertThat(beanDefinition.getScope()).isEqualTo(BeanDefinition.SCOPE_PROTOTYPE);
73+
}
74+
4775
@Test
4876
void registerWhenNotAlreadyRegisteredAddBeanDefinition() {
4977
String beanName = "beancp-" + BeanConfigurationProperties.class.getName();
5078
this.registrar.register(BeanConfigurationProperties.class);
5179
BeanDefinition definition = this.registry.getBeanDefinition(beanName);
5280
assertThat(definition).isNotNull();
81+
assertThat(definition.getScope()).isEqualTo(BeanDefinition.SCOPE_SINGLETON);
5382
assertThat(definition.getBeanClassName()).isEqualTo(BeanConfigurationProperties.class.getName());
5483
}
5584

@@ -99,6 +128,18 @@ static class BeanConfigurationProperties {
99128

100129
}
101130

131+
@ConfigurationProperties(prefix = "scopedbeancp")
132+
@Scope("prototype")
133+
static class ScopedBeanConfigurationProperties {
134+
135+
}
136+
137+
@ConfigurationProperties(prefix = "scopedbeancp")
138+
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS, value = "prototype")
139+
static class ProxyScopedBeanConfigurationProperties {
140+
141+
}
142+
102143
static class NoAnnotationConfigurationProperties {
103144

104145
}

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.Optional;
3434
import java.util.Properties;
3535
import java.util.Set;
36+
import java.util.UUID;
3637

3738
import jakarta.annotation.PostConstruct;
3839
import jakarta.validation.Valid;
@@ -1243,6 +1244,24 @@ void loadWhenBindingToConstructorParametersWithConversionToCustomListImplementat
12431244
"b");
12441245
}
12451246

1247+
@Test
1248+
void loadPrototypeScopedProperties() {
1249+
load(PrototypeScopePropertiesConfiguration.class);
1250+
PrototypeScopeProperties p1 = this.context.getBean(PrototypeScopeProperties.class);
1251+
PrototypeScopeProperties p2 = this.context.getBean(PrototypeScopeProperties.class);
1252+
assertThat(p1.id).isNotNull();
1253+
assertThat(p2.id).isNotNull();
1254+
assertThat(p1.id).isNotEqualTo(p2.id);
1255+
}
1256+
1257+
@Test
1258+
void loadProxyScopedProperties() {
1259+
load(ProxyScopePropertiesConfiguration.class, "name=test");
1260+
ProxyScopeProperties p = this.context.getBean(ProxyScopeProperties.class);
1261+
assertThat(p.name).isNotNull(); // proxy does not work for fields
1262+
assertThat(p.getName()).isEqualTo("test");
1263+
}
1264+
12461265
@Test
12471266
void loadWhenBindingToJavaBeanWithConversionToCustomListImplementation() {
12481267
load(SetterBoundCustomListPropertiesConfiguration.class, "test.values=a,b");
@@ -1493,6 +1512,46 @@ static PropertySourcesPlaceholderConfigurer configurer2() {
14931512

14941513
}
14951514

1515+
@EnableConfigurationProperties(PrototypeScopeProperties.class)
1516+
@Configuration(proxyBeanMethods = false)
1517+
static class PrototypeScopePropertiesConfiguration {
1518+
1519+
}
1520+
1521+
@ConfigurationProperties
1522+
@Scope("prototype")
1523+
static class PrototypeScopeProperties {
1524+
1525+
private final String id = UUID.randomUUID().toString();
1526+
1527+
String getId() {
1528+
return this.id;
1529+
}
1530+
1531+
}
1532+
1533+
@EnableConfigurationProperties(ProxyScopeProperties.class)
1534+
@Configuration(proxyBeanMethods = false)
1535+
static class ProxyScopePropertiesConfiguration {
1536+
1537+
}
1538+
1539+
@ConfigurationProperties
1540+
@Scope("prototype")
1541+
static class ProxyScopeProperties {
1542+
1543+
private String name;
1544+
1545+
String getName() {
1546+
return this.name;
1547+
}
1548+
1549+
void setName(String name) {
1550+
this.name = name;
1551+
}
1552+
1553+
}
1554+
14961555
@Configuration(proxyBeanMethods = false)
14971556
@EnableConfigurationProperties
14981557
static class PrototypePropertiesConfiguration {

0 commit comments

Comments
 (0)