Skip to content

Commit fb4b26a

Browse files
committed
Merge branch '3.1.x'
2 parents 4a34015 + 1652c27 commit fb4b26a

File tree

2 files changed

+74
-5
lines changed

2 files changed

+74
-5
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import java.util.Optional;
3131
import java.util.Properties;
3232
import java.util.Set;
33+
import java.util.concurrent.atomic.AtomicBoolean;
3334
import java.util.stream.Stream;
3435

3536
import org.apache.commons.logging.Log;
@@ -1457,10 +1458,10 @@ public Augmented with(Class<?>... sources) {
14571458
*/
14581459
public SpringApplication.Running run(String... args) {
14591460
RunListener runListener = new RunListener();
1460-
SpringApplicationHook hook = (springApplication) -> {
1461+
SpringApplicationHook hook = new SingleUseSpringApplicationHook((springApplication) -> {
14611462
springApplication.addPrimarySources(this.sources);
14621463
return runListener;
1463-
};
1464+
});
14641465
withHook(hook, () -> this.main.accept(args));
14651466
return runListener;
14661467
}
@@ -1580,4 +1581,21 @@ public ConfigurableApplicationContext getApplicationContext() {
15801581

15811582
}
15821583

1584+
private static final class SingleUseSpringApplicationHook implements SpringApplicationHook {
1585+
1586+
private final AtomicBoolean used = new AtomicBoolean();
1587+
1588+
private final SpringApplicationHook delegate;
1589+
1590+
private SingleUseSpringApplicationHook(SpringApplicationHook delegate) {
1591+
this.delegate = delegate;
1592+
}
1593+
1594+
@Override
1595+
public SpringApplicationRunListener getRunListener(SpringApplication springApplication) {
1596+
return this.used.compareAndSet(false, true) ? this.delegate.getRunListener(springApplication) : null;
1597+
}
1598+
1599+
}
1600+
15831601
}

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.List;
2525
import java.util.Map;
2626
import java.util.Set;
27+
import java.util.concurrent.atomic.AtomicBoolean;
2728
import java.util.concurrent.atomic.AtomicInteger;
2829
import java.util.concurrent.atomic.AtomicReference;
2930
import java.util.function.Supplier;
@@ -1363,18 +1364,30 @@ void shouldUseAotInitializer() {
13631364
@Test
13641365
void fromRunsWithAdditionalSources() {
13651366
assertThat(ExampleAdditionalConfig.local.get()).isNull();
1366-
SpringApplication.from(ExampleFromMainMethod::main).with(ExampleAdditionalConfig.class).run();
1367+
this.context = SpringApplication.from(ExampleFromMainMethod::main)
1368+
.with(ExampleAdditionalConfig.class)
1369+
.run()
1370+
.getApplicationContext();
13671371
assertThat(ExampleAdditionalConfig.local.get()).isNotNull();
13681372
ExampleAdditionalConfig.local.set(null);
13691373
}
13701374

13711375
@Test
13721376
void fromReturnsApplicationContext() {
1373-
ConfigurableApplicationContext context = SpringApplication.from(ExampleFromMainMethod::main)
1377+
this.context = SpringApplication.from(ExampleFromMainMethod::main)
13741378
.with(ExampleAdditionalConfig.class)
13751379
.run()
13761380
.getApplicationContext();
1377-
assertThat(context).isNotNull();
1381+
assertThat(this.context).isNotNull();
1382+
}
1383+
1384+
@Test
1385+
void fromWithMultipleApplicationsOnlyAppliesAdditionalSourcesOnce() {
1386+
this.context = SpringApplication.from(MultipleApplicationsMainMethod::main)
1387+
.with(SingleUseAdditionalConfig.class)
1388+
.run()
1389+
.getApplicationContext();
1390+
assertThatNoException().isThrownBy(() -> this.context.getBean(SingleUseAdditionalConfig.class));
13781391
}
13791392

13801393
private <S extends AvailabilityState> ArgumentMatcher<ApplicationEvent> isAvailabilityChangeEventWithState(
@@ -1949,6 +1962,31 @@ static void main(String[] args) {
19491962

19501963
}
19511964

1965+
static class MultipleApplicationsMainMethod {
1966+
1967+
static void main(String[] args) {
1968+
SpringApplication application = new SpringApplication(ExampleConfig.class);
1969+
application.setWebApplicationType(WebApplicationType.NONE);
1970+
application.addListeners(new ApplicationListener<ApplicationEnvironmentPreparedEvent>() {
1971+
1972+
@Override
1973+
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
1974+
SpringApplicationBuilder builder = new SpringApplicationBuilder(
1975+
InnerApplicationConfiguration.class);
1976+
builder.web(WebApplicationType.NONE);
1977+
builder.run().close();
1978+
}
1979+
1980+
});
1981+
application.run(args);
1982+
}
1983+
1984+
static class InnerApplicationConfiguration {
1985+
1986+
}
1987+
1988+
}
1989+
19521990
@Configuration
19531991
static class ExampleAdditionalConfig {
19541992

@@ -1960,4 +1998,17 @@ static class ExampleAdditionalConfig {
19601998

19611999
}
19622000

2001+
@Configuration
2002+
static class SingleUseAdditionalConfig {
2003+
2004+
private static AtomicBoolean used = new AtomicBoolean(false);
2005+
2006+
SingleUseAdditionalConfig() {
2007+
if (!used.compareAndSet(false, true)) {
2008+
throw new IllegalStateException("Single-use configuration has already been used");
2009+
}
2010+
}
2011+
2012+
}
2013+
19632014
}

0 commit comments

Comments
 (0)