Skip to content

Commit 4313905

Browse files
authored
Merge pull request #1720 from ryanjbaxter/fix-1716
Autowire beans when rebinding
2 parents ebb66aa + 56ceea5 commit 4313905

2 files changed

Lines changed: 128 additions & 0 deletions

File tree

spring-cloud-context/src/main/java/org/springframework/cloud/context/properties/ConfigurationPropertiesRebinder.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,14 @@ private boolean rebind(String name, ApplicationContext appContext) {
174174
else {
175175
appContext.getAutowireCapableBeanFactory().destroyBean(target);
176176
resetBeanToDefaults(target);
177+
appContext.getAutowireCapableBeanFactory().autowireBean(target);
177178
appContext.getAutowireCapableBeanFactory().initializeBean(target, name);
178179
}
179180
}
180181
else {
181182
appContext.getAutowireCapableBeanFactory().destroyBean(bean);
182183
resetBeanToDefaults(bean);
184+
appContext.getAutowireCapableBeanFactory().autowireBean(bean);
183185
appContext.getAutowireCapableBeanFactory().initializeBean(bean, name);
184186
}
185187
return true;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* Copyright 2012-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.context.properties;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import org.springframework.beans.factory.annotation.Autowired;
22+
import org.springframework.beans.factory.annotation.Value;
23+
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
24+
import org.springframework.boot.context.properties.ConfigurationProperties;
25+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
26+
import org.springframework.boot.test.context.SpringBootTest;
27+
import org.springframework.boot.test.util.TestPropertyValues;
28+
import org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration;
29+
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
30+
import org.springframework.cloud.context.properties.ConfigurationPropertiesRebinderValueFieldIntegrationTests.TestConfiguration;
31+
import org.springframework.context.ApplicationContext;
32+
import org.springframework.context.annotation.Bean;
33+
import org.springframework.context.annotation.Configuration;
34+
import org.springframework.context.annotation.Import;
35+
import org.springframework.core.env.ConfigurableEnvironment;
36+
import org.springframework.test.annotation.DirtiesContext;
37+
38+
import static org.assertj.core.api.BDDAssertions.then;
39+
40+
/**
41+
* Verifies that a {@code @Value}-injected field on a non-proxied
42+
* {@code @ConfigurationProperties} bean survives a rebind even when the field is not
43+
* reachable under the bean's own prefix (for example
44+
* {@code ConsulDiscoveryProperties#aclToken}). See gh-1716.
45+
*
46+
* @author Ryan Baxter
47+
*/
48+
@SpringBootTest(classes = TestConfiguration.class, properties = { "test.message=Hello", "secret.token=secret-value" })
49+
public class ConfigurationPropertiesRebinderValueFieldIntegrationTests {
50+
51+
@Autowired
52+
private TestProperties properties;
53+
54+
@Autowired
55+
private ConfigurationPropertiesRebinder rebinder;
56+
57+
@Autowired
58+
private ConfigurableEnvironment environment;
59+
60+
@Test
61+
@DirtiesContext
62+
public void valueInjectedFieldSurvivesRebind() {
63+
then(this.properties.getMessage()).isEqualTo("Hello");
64+
then(this.properties.getToken()).isEqualTo("secret-value");
65+
// Change a property under the bean's own prefix and rebind
66+
TestPropertyValues.of("test.message=World").applyTo(this.environment);
67+
this.rebinder.rebind();
68+
// The rebind picks up the new value under the bean's prefix...
69+
then(this.properties.getMessage()).isEqualTo("World");
70+
// ...and the @Value field, which is outside that prefix, is not lost
71+
then(this.properties.getToken()).isEqualTo("secret-value");
72+
}
73+
74+
@Configuration(proxyBeanMethods = false)
75+
@EnableConfigurationProperties
76+
@Import({ RefreshConfiguration.RebinderConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
77+
protected static class TestConfiguration {
78+
79+
@Bean
80+
protected TestProperties testProperties() {
81+
return new TestProperties();
82+
}
83+
84+
}
85+
86+
// Hack out a protected inner class for testing
87+
protected static class RefreshConfiguration extends RefreshAutoConfiguration {
88+
89+
@Configuration(proxyBeanMethods = false)
90+
protected static class RebinderConfiguration extends ConfigurationPropertiesRebinderAutoConfiguration {
91+
92+
public RebinderConfiguration(ApplicationContext context) {
93+
super(context);
94+
}
95+
96+
}
97+
98+
}
99+
100+
@ConfigurationProperties("test")
101+
protected static class TestProperties {
102+
103+
@Value("${secret.token:}")
104+
private String token;
105+
106+
private String message;
107+
108+
public String getToken() {
109+
return this.token;
110+
}
111+
112+
public void setToken(String token) {
113+
this.token = token;
114+
}
115+
116+
public String getMessage() {
117+
return this.message;
118+
}
119+
120+
public void setMessage(String message) {
121+
this.message = message;
122+
}
123+
124+
}
125+
126+
}

0 commit comments

Comments
 (0)