Merge branch '3.1.x'

This commit is contained in:
Andy Wilkinson 2023-06-16 10:45:44 +01:00
commit fb4b26a842
2 changed files with 74 additions and 5 deletions

View File

@ -30,6 +30,7 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Stream;
import org.apache.commons.logging.Log;
@ -1457,10 +1458,10 @@ public class SpringApplication {
*/
public SpringApplication.Running run(String... args) {
RunListener runListener = new RunListener();
SpringApplicationHook hook = (springApplication) -> {
SpringApplicationHook hook = new SingleUseSpringApplicationHook((springApplication) -> {
springApplication.addPrimarySources(this.sources);
return runListener;
};
});
withHook(hook, () -> this.main.accept(args));
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;
}
}
}

View File

@ -24,6 +24,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
@ -1363,18 +1364,30 @@ class SpringApplicationTests {
@Test
void fromRunsWithAdditionalSources() {
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();
ExampleAdditionalConfig.local.set(null);
}
@Test
void fromReturnsApplicationContext() {
ConfigurableApplicationContext context = SpringApplication.from(ExampleFromMainMethod::main)
this.context = SpringApplication.from(ExampleFromMainMethod::main)
.with(ExampleAdditionalConfig.class)
.run()
.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(
@ -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
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");
}
}
}
}