Merge branch '3.1.x'

pull/35935/head
Andy Wilkinson 1 year ago
commit fb4b26a842

@ -30,6 +30,7 @@ import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -1457,10 +1458,10 @@ public class SpringApplication {
*/ */
public SpringApplication.Running run(String... args) { public SpringApplication.Running run(String... args) {
RunListener runListener = new RunListener(); RunListener runListener = new RunListener();
SpringApplicationHook hook = (springApplication) -> { SpringApplicationHook hook = new SingleUseSpringApplicationHook((springApplication) -> {
springApplication.addPrimarySources(this.sources); springApplication.addPrimarySources(this.sources);
return runListener; return runListener;
}; });
withHook(hook, () -> this.main.accept(args)); withHook(hook, () -> this.main.accept(args));
return runListener; return runListener;
} }
@ -1580,4 +1581,21 @@ public class SpringApplication {
} }
private static final class SingleUseSpringApplicationHook implements SpringApplicationHook {
private final AtomicBoolean used = new AtomicBoolean();
private final SpringApplicationHook delegate;
private SingleUseSpringApplicationHook(SpringApplicationHook delegate) {
this.delegate = delegate;
}
@Override
public SpringApplicationRunListener getRunListener(SpringApplication springApplication) {
return this.used.compareAndSet(false, true) ? this.delegate.getRunListener(springApplication) : null;
}
}
} }

@ -24,6 +24,7 @@ import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -1363,18 +1364,30 @@ class SpringApplicationTests {
@Test @Test
void fromRunsWithAdditionalSources() { void fromRunsWithAdditionalSources() {
assertThat(ExampleAdditionalConfig.local.get()).isNull(); assertThat(ExampleAdditionalConfig.local.get()).isNull();
SpringApplication.from(ExampleFromMainMethod::main).with(ExampleAdditionalConfig.class).run(); this.context = SpringApplication.from(ExampleFromMainMethod::main)
.with(ExampleAdditionalConfig.class)
.run()
.getApplicationContext();
assertThat(ExampleAdditionalConfig.local.get()).isNotNull(); assertThat(ExampleAdditionalConfig.local.get()).isNotNull();
ExampleAdditionalConfig.local.set(null); ExampleAdditionalConfig.local.set(null);
} }
@Test @Test
void fromReturnsApplicationContext() { void fromReturnsApplicationContext() {
ConfigurableApplicationContext context = SpringApplication.from(ExampleFromMainMethod::main) this.context = SpringApplication.from(ExampleFromMainMethod::main)
.with(ExampleAdditionalConfig.class) .with(ExampleAdditionalConfig.class)
.run() .run()
.getApplicationContext(); .getApplicationContext();
assertThat(context).isNotNull(); assertThat(this.context).isNotNull();
}
@Test
void fromWithMultipleApplicationsOnlyAppliesAdditionalSourcesOnce() {
this.context = SpringApplication.from(MultipleApplicationsMainMethod::main)
.with(SingleUseAdditionalConfig.class)
.run()
.getApplicationContext();
assertThatNoException().isThrownBy(() -> this.context.getBean(SingleUseAdditionalConfig.class));
} }
private <S extends AvailabilityState> ArgumentMatcher<ApplicationEvent> isAvailabilityChangeEventWithState( private <S extends AvailabilityState> ArgumentMatcher<ApplicationEvent> isAvailabilityChangeEventWithState(
@ -1949,6 +1962,31 @@ class SpringApplicationTests {
} }
static class MultipleApplicationsMainMethod {
static void main(String[] args) {
SpringApplication application = new SpringApplication(ExampleConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.addListeners(new ApplicationListener<ApplicationEnvironmentPreparedEvent>() {
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
SpringApplicationBuilder builder = new SpringApplicationBuilder(
InnerApplicationConfiguration.class);
builder.web(WebApplicationType.NONE);
builder.run().close();
}
});
application.run(args);
}
static class InnerApplicationConfiguration {
}
}
@Configuration @Configuration
static class ExampleAdditionalConfig { static class ExampleAdditionalConfig {
@ -1960,4 +1998,17 @@ class SpringApplicationTests {
} }
@Configuration
static class SingleUseAdditionalConfig {
private static AtomicBoolean used = new AtomicBoolean(false);
SingleUseAdditionalConfig() {
if (!used.compareAndSet(false, true)) {
throw new IllegalStateException("Single-use configuration has already been used");
}
}
}
} }

Loading…
Cancel
Save