Skip to content

Commit b5ef5a2

Browse files
committed
Merge branch '2.5.x'
Closes gh-27408
2 parents f7290b2 + 9d2cb16 commit b5ef5a2

File tree

2 files changed

+86
-30
lines changed

2 files changed

+86
-30
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/sql/init/dependency/DatabaseInitializationDependencyConfigurer.java

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
import java.util.Collection;
2121
import java.util.Collections;
2222
import java.util.HashSet;
23+
import java.util.LinkedHashMap;
2324
import java.util.LinkedHashSet;
2425
import java.util.List;
26+
import java.util.Map;
2527
import java.util.Set;
2628

2729
import org.springframework.beans.factory.BeanFactory;
@@ -38,6 +40,7 @@
3840
import org.springframework.core.env.Environment;
3941
import org.springframework.core.io.support.SpringFactoriesLoader;
4042
import org.springframework.core.type.AnnotationMetadata;
43+
import org.springframework.util.CollectionUtils;
4144
import org.springframework.util.StringUtils;
4245

4346
/**
@@ -100,48 +103,49 @@ public int getOrder() {
100103

101104
@Override
102105
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
103-
Set<String> initializerBeanNames = detectInitializerBeanNames(beanFactory);
106+
InitializerBeanNames initializerBeanNames = detectInitializerBeanNames(beanFactory);
104107
if (initializerBeanNames.isEmpty()) {
105108
return;
106109
}
107-
String previousInitializerBeanName = null;
108-
for (String initializerBeanName : initializerBeanNames) {
109-
BeanDefinition beanDefinition = getBeanDefinition(initializerBeanName, beanFactory);
110-
beanDefinition.setDependsOn(merge(beanDefinition.getDependsOn(), previousInitializerBeanName));
111-
previousInitializerBeanName = initializerBeanName;
110+
Set<String> previousInitializerBeanNamesBatch = null;
111+
for (Set<String> initializerBeanNamesBatch : initializerBeanNames.batchedBeanNames()) {
112+
for (String initializerBeanName : initializerBeanNamesBatch) {
113+
BeanDefinition beanDefinition = getBeanDefinition(initializerBeanName, beanFactory);
114+
beanDefinition
115+
.setDependsOn(merge(beanDefinition.getDependsOn(), previousInitializerBeanNamesBatch));
116+
}
117+
previousInitializerBeanNamesBatch = initializerBeanNamesBatch;
112118
}
113119
for (String dependsOnInitializationBeanNames : detectDependsOnInitializationBeanNames(beanFactory)) {
114120
BeanDefinition beanDefinition = getBeanDefinition(dependsOnInitializationBeanNames, beanFactory);
115-
beanDefinition.setDependsOn(merge(beanDefinition.getDependsOn(), initializerBeanNames));
121+
beanDefinition.setDependsOn(merge(beanDefinition.getDependsOn(), initializerBeanNames.beanNames()));
116122
}
117123
}
118124

119-
private String[] merge(String[] source, String additional) {
120-
return merge(source, (additional != null) ? Collections.singleton(additional) : Collections.emptySet());
121-
}
122-
123125
private String[] merge(String[] source, Set<String> additional) {
126+
if (CollectionUtils.isEmpty(additional)) {
127+
return source;
128+
}
124129
Set<String> result = new LinkedHashSet<>((source != null) ? Arrays.asList(source) : Collections.emptySet());
125130
result.addAll(additional);
126131
return StringUtils.toStringArray(result);
127132
}
128133

129-
private Set<String> detectInitializerBeanNames(ConfigurableListableBeanFactory beanFactory) {
134+
private InitializerBeanNames detectInitializerBeanNames(ConfigurableListableBeanFactory beanFactory) {
130135
List<DatabaseInitializerDetector> detectors = getDetectors(beanFactory, DatabaseInitializerDetector.class);
131-
Set<String> beanNames = new LinkedHashSet<>();
136+
InitializerBeanNames initializerBeanNames = new InitializerBeanNames();
132137
for (DatabaseInitializerDetector detector : detectors) {
133138
for (String beanName : detector.detect(beanFactory)) {
134139
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
135140
beanDefinition.setAttribute(DatabaseInitializerDetector.class.getName(),
136141
detector.getClass().getName());
137-
beanNames.add(beanName);
142+
initializerBeanNames.detected(detector, beanName);
138143
}
139144
}
140-
beanNames = Collections.unmodifiableSet(beanNames);
141145
for (DatabaseInitializerDetector detector : detectors) {
142-
detector.detectionComplete(beanFactory, beanNames);
146+
detector.detectionComplete(beanFactory, initializerBeanNames.beanNames());
143147
}
144-
return beanNames;
148+
return initializerBeanNames;
145149
}
146150

147151
private Collection<String> detectDependsOnInitializationBeanNames(ConfigurableListableBeanFactory beanFactory) {
@@ -174,6 +178,31 @@ private static BeanDefinition getBeanDefinition(String beanName, ConfigurableLis
174178
}
175179
}
176180

181+
static class InitializerBeanNames {
182+
183+
private final Map<DatabaseInitializerDetector, Set<String>> byDetectorBeanNames = new LinkedHashMap<>();
184+
185+
private final Set<String> beanNames = new LinkedHashSet<>();
186+
187+
private void detected(DatabaseInitializerDetector detector, String beanName) {
188+
this.byDetectorBeanNames.computeIfAbsent(detector, (key) -> new LinkedHashSet<>()).add(beanName);
189+
this.beanNames.add(beanName);
190+
}
191+
192+
private boolean isEmpty() {
193+
return this.beanNames.isEmpty();
194+
}
195+
196+
private Iterable<Set<String>> batchedBeanNames() {
197+
return this.byDetectorBeanNames.values();
198+
}
199+
200+
private Set<String> beanNames() {
201+
return Collections.unmodifiableSet(this.beanNames);
202+
}
203+
204+
}
205+
177206
}
178207

179208
}

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/sql/init/dependency/DatabaseInitializationDependencyConfigurerTests.java

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.Enumeration;
2727
import java.util.HashMap;
2828
import java.util.HashSet;
29+
import java.util.LinkedHashSet;
2930
import java.util.List;
3031
import java.util.Map;
3132
import java.util.Properties;
@@ -71,7 +72,8 @@ class DatabaseInitializationDependencyConfigurerTests {
7172

7273
@BeforeEach
7374
void resetMocks() {
74-
reset(MockDatabaseInitializerDetector.instance, OrderedMockDatabaseInitializerDetector.instance,
75+
reset(MockDatabaseInitializerDetector.instance, OrderedNearLowestMockDatabaseInitializerDetector.instance,
76+
OrderedLowestMockDatabaseInitializerDetector.instance,
7577
MockedDependsOnDatabaseInitializationDetector.instance);
7678
}
7779

@@ -94,8 +96,7 @@ void beanFactoryPostProcessorHasOrderAllowingSubsequentPostProcessorsToFineTuneD
9496
context.refresh();
9597
assertThat(DependsOnCaptor.dependsOn).hasEntrySatisfying("bravo",
9698
(dependencies) -> assertThat(dependencies).containsExactly("alpha"));
97-
assertThat(DependsOnCaptor.dependsOn).hasEntrySatisfying("alpha",
98-
(dependencies) -> assertThat(dependencies).isEmpty());
99+
assertThat(DependsOnCaptor.dependsOn).doesNotContainKey("alpha");
99100
});
100101
}
101102

@@ -140,24 +141,34 @@ void whenDependenciesAreConfiguredThenBeansThatDependUponDatabaseInitializationD
140141
@Test
141142
void whenDependenciesAreConfiguredDetectedDatabaseInitializersAreInitializedInCorrectOrder() {
142143
BeanDefinition alpha = BeanDefinitionBuilder.genericBeanDefinition(String.class).getBeanDefinition();
143-
BeanDefinition bravo = BeanDefinitionBuilder.genericBeanDefinition(String.class).getBeanDefinition();
144+
BeanDefinition bravo1 = BeanDefinitionBuilder.genericBeanDefinition(String.class).getBeanDefinition();
145+
BeanDefinition bravo2 = BeanDefinitionBuilder.genericBeanDefinition(String.class).getBeanDefinition();
144146
BeanDefinition charlie = BeanDefinitionBuilder.genericBeanDefinition(String.class).getBeanDefinition();
145-
performDetection(Arrays.asList(MockDatabaseInitializerDetector.class,
146-
OrderedMockDatabaseInitializerDetector.class, MockedDependsOnDatabaseInitializationDetector.class),
147+
BeanDefinition delta = BeanDefinitionBuilder.genericBeanDefinition(String.class).getBeanDefinition();
148+
performDetection(
149+
Arrays.asList(MockDatabaseInitializerDetector.class, OrderedLowestMockDatabaseInitializerDetector.class,
150+
OrderedNearLowestMockDatabaseInitializerDetector.class,
151+
MockedDependsOnDatabaseInitializationDetector.class),
147152
(context) -> {
148153
given(MockDatabaseInitializerDetector.instance.detect(context.getBeanFactory()))
149154
.willReturn(Collections.singleton("alpha"));
150-
given(OrderedMockDatabaseInitializerDetector.instance.detect(context.getBeanFactory()))
151-
.willReturn(Collections.singleton("bravo"));
155+
given(OrderedNearLowestMockDatabaseInitializerDetector.instance.detect(context.getBeanFactory()))
156+
.willReturn(new LinkedHashSet<>(Arrays.asList("bravo1", "bravo2")));
157+
given(OrderedLowestMockDatabaseInitializerDetector.instance.detect(context.getBeanFactory()))
158+
.willReturn(new LinkedHashSet<>(Arrays.asList("charlie")));
152159
given(MockedDependsOnDatabaseInitializationDetector.instance.detect(context.getBeanFactory()))
153-
.willReturn(Collections.singleton("charlie"));
160+
.willReturn(Collections.singleton("delta"));
154161
context.registerBeanDefinition("alpha", alpha);
155-
context.registerBeanDefinition("bravo", bravo);
162+
context.registerBeanDefinition("bravo1", bravo1);
163+
context.registerBeanDefinition("bravo2", bravo2);
156164
context.registerBeanDefinition("charlie", charlie);
165+
context.registerBeanDefinition("delta", delta);
157166
context.register(DependencyConfigurerConfiguration.class);
158167
context.refresh();
159-
assertThat(charlie.getDependsOn()).containsExactly("alpha", "bravo");
160-
assertThat(bravo.getDependsOn()).containsExactly("alpha");
168+
assertThat(delta.getDependsOn()).containsExactlyInAnyOrder("alpha", "bravo1", "bravo2", "charlie");
169+
assertThat(charlie.getDependsOn()).containsExactly("bravo1", "bravo2");
170+
assertThat(bravo1.getDependsOn()).containsExactly("alpha");
171+
assertThat(bravo2.getDependsOn()).containsExactly("alpha");
161172
assertThat(alpha.getDependsOn()).isNullOrEmpty();
162173
});
163174
}
@@ -227,7 +238,7 @@ public void detectionComplete(ConfigurableListableBeanFactory beanFactory,
227238

228239
}
229240

230-
static class OrderedMockDatabaseInitializerDetector implements DatabaseInitializerDetector {
241+
static class OrderedLowestMockDatabaseInitializerDetector implements DatabaseInitializerDetector {
231242

232243
private static DatabaseInitializerDetector instance = mock(DatabaseInitializerDetector.class);
233244

@@ -243,6 +254,22 @@ public int getOrder() {
243254

244255
}
245256

257+
static class OrderedNearLowestMockDatabaseInitializerDetector implements DatabaseInitializerDetector {
258+
259+
private static DatabaseInitializerDetector instance = mock(DatabaseInitializerDetector.class);
260+
261+
@Override
262+
public Set<String> detect(ConfigurableListableBeanFactory beanFactory) {
263+
return instance.detect(beanFactory);
264+
}
265+
266+
@Override
267+
public int getOrder() {
268+
return Ordered.LOWEST_PRECEDENCE - 100;
269+
}
270+
271+
}
272+
246273
static class MockedDependsOnDatabaseInitializationDetector implements DependsOnDatabaseInitializationDetector {
247274

248275
private static DependsOnDatabaseInitializationDetector instance = mock(

0 commit comments

Comments
 (0)