下面列出了org.springframework.boot.SpringApplication#exit ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
public static void main(String[] args) throws Exception {
// below is output *before* logging is configured so will appear on console
logVersionInfo();
try {
SpringApplication
.exit(new SpringApplicationBuilder(FilterTool.class)
.properties("spring.config.location:${config:null}")
.properties("spring.profiles.active:" + Modules.REPLICATION)
.properties("instance.home:${user.home}")
.properties("instance.name:${source-catalog.name}_${replica-catalog.name}")
.bannerMode(Mode.OFF)
.registerShutdownHook(true)
.build()
.run(args));
} catch (BeanCreationException e) {
Throwable mostSpecificCause = e.getMostSpecificCause();
if (mostSpecificCause instanceof BindException) {
printFilterToolHelp(((BindException) mostSpecificCause).getAllErrors());
}
throw e;
}
}
public static void main(String[] args) {
// 重构前的实现
// new SpringApplicationBuilder(ExitCodeGeneratorBootstrap.class)
// .web(false) // 非 Web 应用
// .run(args) // 运行 SpringBoot 应用
// .close(); // 关闭应用上下文
// 重构后的实现
int exitCode = SpringApplication.exit(new SpringApplicationBuilder(ExitCodeGeneratorBootstrap.class)
.web(false) // 非 Web 应用
.run(args) // 运行 SpringBoot 应用
);
// 传递退出码到 System#exit(int) 方法
System.exit(exitCode);
}
public static void main(String[] args) throws Exception {
// below is output *before* logging is configured so will appear on console
logVersionInfo();
try {
SpringApplication
.exit(new SpringApplicationBuilder(ComparisonTool.class)
.properties("spring.config.location:${config:null}")
.properties("spring.profiles.active:" + Modules.REPLICATION)
.properties("instance.home:${user.home}")
.properties("instance.name:${source-catalog.name}_${replica-catalog.name}")
.bannerMode(Mode.OFF)
.registerShutdownHook(true)
.build()
.run(args));
} catch (BeanCreationException e) {
Throwable mostSpecificCause = e.getMostSpecificCause();
if (mostSpecificCause instanceof BindException) {
printComparisonToolHelp(((BindException) mostSpecificCause).getAllErrors());
throw e;
}
if (e.getMostSpecificCause() instanceof IllegalArgumentException) {
LOG.error(e.getMessage(), e);
printComparisonToolHelp(Collections.<ObjectError>emptyList());
}
}
}
@DataProvider(value = {
"MANUAL_IMPORT_ONLY",
"COMPONENT_SCAN_ONLY",
"BOTH_MANUAL_AND_COMPONENT_SCAN"
})
@Test
public void component_test(ComponentTestSetup componentTestSetup) {
// given
int serverPort = findFreePort();
Class<?> mainClass = componentTestSetup.mainClass;
ConfigurableApplicationContext serverAppContext = SpringApplication.run(mainClass, "--server.port=" + serverPort);
try {
// when
WingtipsSpringBootConfiguration config = serverAppContext.getBean(WingtipsSpringBootConfiguration.class);
WingtipsSpringBootProperties props = serverAppContext.getBean(WingtipsSpringBootProperties.class);
String[] someComponentScannedClassBeanNames =
serverAppContext.getBeanNamesForType(SomeComponentScannedClass.class);
// then
// Sanity check that we component scanned (or not) as appropriate.
if (componentTestSetup.expectComponentScannedObjects) {
assertThat(someComponentScannedClassBeanNames).isNotEmpty();
}
else {
assertThat(someComponentScannedClassBeanNames).isEmpty();
}
// WingtipsSpringBootConfiguration and WingtipsSpringBootProperties should be available as beans, and
// the config should use the same props we received.
assertThat(config).isNotNull();
assertThat(props).isNotNull();
assertThat(config.wingtipsProperties).isSameAs(props);
}
finally {
SpringApplication.exit(serverAppContext);
}
}
public static void main(String[] args)
throws InvalidTopologyException, AuthorizationException, AlreadyAliveException, InterruptedException {
ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
AppMain appMain = context.getBean(AppMain.class);
appMain.Laugher();
SpringApplication.exit(context);
}
@DataProvider(value = {
"MANUAL_IMPORT_ONLY",
"COMPONENT_SCAN_ONLY",
"BOTH_MANUAL_AND_COMPONENT_SCAN"
})
@Test
public void component_test(ComponentTestSetup componentTestSetup) {
// given
int serverPort = findFreePort();
Class<?> mainClass = componentTestSetup.mainClass;
ConfigurableApplicationContext serverAppContext = SpringApplication.run(mainClass,
"--server.port=" + serverPort);
try {
// when
WingtipsSpringBoot2WebfluxConfiguration
config = serverAppContext.getBean(WingtipsSpringBoot2WebfluxConfiguration.class);
WingtipsSpringBoot2WebfluxProperties props =
serverAppContext.getBean(WingtipsSpringBoot2WebfluxProperties.class);
String[] someComponentScannedClassBeanNames =
serverAppContext.getBeanNamesForType(SomeComponentScannedClass.class);
// then
// Sanity check that we component scanned (or not) as appropriate.
if (componentTestSetup.expectComponentScannedObjects) {
assertThat(someComponentScannedClassBeanNames).isNotEmpty();
} else {
assertThat(someComponentScannedClassBeanNames).isEmpty();
}
// WingtipsSpringBoot2WebfluxConfiguration and WingtipsSpringBoot2WebfluxProperties should be available as
// beans, and the config should use the same props we received.
assertThat(config).isNotNull();
assertThat(props).isNotNull();
assertThat(config.wingtipsProperties).isSameAs(props);
// The config should not have any custom WingtipsSpringWebfluxWebFilter. Spring will populate
// the config.customSpringWebfluxWebFilter field with whatever wingtipsSpringWebfluxWebFilter()
// produces - so they should be the same.
Map<String, WingtipsSpringWebfluxWebFilter> filtersFromSpring =
serverAppContext.getBeansOfType(WingtipsSpringWebfluxWebFilter.class);
assertThat(filtersFromSpring).isEqualTo(
Collections.singletonMap("wingtipsSpringWebfluxWebFilter", config.customSpringWebfluxWebFilter)
);
} finally {
Schedulers.removeExecutorServiceDecorator(WingtipsReactorInitializer.WINGTIPS_SCHEDULER_KEY);
SpringApplication.exit(serverAppContext);
}
}
@Override
public void run(String... args) throws Exception {
SpringApplication.exit(this.applicationContext, new ShellExitCodeGenerator(this.doRun()));
}
@Test
public void component_test_with_custom_WingtipsSpringWebfluxWebFilter() {
// given
int serverPort = findFreePort();
ConfigurableApplicationContext serverAppContext = SpringApplication.run(
ComponentTestMainWithCustomWingtipsWebFilter.class,
"--server.port=" + serverPort
);
try {
// when
WingtipsSpringBoot2WebfluxConfiguration
config = serverAppContext.getBean(WingtipsSpringBoot2WebfluxConfiguration.class);
WingtipsSpringBoot2WebfluxProperties props =
serverAppContext.getBean(WingtipsSpringBoot2WebfluxProperties.class);
String[] someComponentScannedClassBeanNames =
serverAppContext.getBeanNamesForType(SomeComponentScannedClass.class);
// then
// Sanity check that we component scanned (or not) as appropriate. This particular component test does
// include component scanning.
assertThat(someComponentScannedClassBeanNames).isNotEmpty();
// WingtipsSpringBoot2WebfluxConfiguration and WingtipsSpringBoot2WebfluxProperties should be available as
// beans, and the config should use the same props we received.
assertThat(config).isNotNull();
assertThat(props).isNotNull();
assertThat(config.wingtipsProperties).isSameAs(props);
// Finally, the thing this test is verifying: the config's custom filter should be the same one from the
// component test main class, and it should be the one that Spring exposes.
assertThat(config.customSpringWebfluxWebFilter)
.isSameAs(ComponentTestMainWithCustomWingtipsWebFilter.customFilter);
Map<String, WingtipsSpringWebfluxWebFilter> filtersFromSpring =
serverAppContext.getBeansOfType(WingtipsSpringWebfluxWebFilter.class);
assertThat(filtersFromSpring).isEqualTo(
Collections.singletonMap("customFilter", ComponentTestMainWithCustomWingtipsWebFilter.customFilter)
);
} finally {
SpringApplication.exit(serverAppContext);
}
}
@AfterClass
public static void afterClass() {
SpringApplication.exit(serverAppContext);
}
@AfterClass
public static void afterClass() {
SpringApplication.exit(classpathScanServerAppContext);
SpringApplication.exit(directImportServerAppContext);
}
@AfterClass
public static void afterClass() {
SpringApplication.exit(serverAppContext);
}
@AfterClass
public static void afterClass() {
SpringApplication.exit(serverAppContext);
}
public static void stop () {
SpringApplication.exit (RequestMonitor.context, new JobExecutionExitCodeGenerator ());
}
public static void stop(ConfigurableApplicationContext context) {
SpringApplication.exit(context, () -> 0);
}
public static void stop() {
SpringApplication.exit(applicationContext);
}
private static void closeApplicationContext() {
SpringApplication.exit(applicationContext);
}
public void shutDown(ExecutorServiceExitCodeGenerator executorServiceExitCodeGenerator) {
SpringApplication.exit(applicationContext, executorServiceExitCodeGenerator);
}
public static void stop () {
SpringApplication.exit (StupidHttpServer.context, new JobExecutionExitCodeGenerator ());
}
@DataProvider(value = {
"MANUAL_IMPORT_ONLY | true",
"COMPONENT_SCAN_ONLY | true",
"COMPONENT_SCAN_WITHOUT_REACTOR_SUPPORT | false",
"BOTH_MANUAL_AND_COMPONENT_SCAN | true"
}, splitBy = "\\|")
@Test
public void project_reactor_wingtips_integration_should_work_as_expected_when_using_publishOn(
ComponentTestSetup componentTestSetup,
boolean expectTracingToPropagate
) {
// given
int serverPort = findFreePort();
Class<?> mainClass = componentTestSetup.mainClass;
ConfigurableApplicationContext serverAppContext = SpringApplication.run(
mainClass, "--server.port=" + serverPort
);
try {
// given
// Setup the mono before we even start the trace.
Mono<Pair<Long, Span>> asyncThreadAndTraceId =
Mono.just("test")
// Set up an async boundary using publishOn(...).
// WARNING: This MUST be a new*() (e.g. newElastic()), rather than the built-in defaults
// like Schedulers.elastic(). Otherwise it's a race condition, as the schedulers are cached
// after they are created and used, so setting the Wingtips+Reactor scheduler hook after
// a default scheduler has been used won't work. Think one test running without the hook, and
// then a different test trying to run with the hook. The second test won't work.
// By using a new scheduler, we guarantee that it will receive whatever hook we setup as part
// of *this* test.
.publishOn(Schedulers.newElastic("someNewElasticScheduler"))
// Return the thread ID and current span.
.map(s -> Pair.of(Thread.currentThread().getId(), Tracer.getInstance().getCurrentSpan()));
// Start the trace and track the thread ID we're on.
final Span rootSpan = Tracer.getInstance().startRequestWithRootSpan("root");
final long mainThreadId = Thread.currentThread().getId();
// when
// This block() is where the subscription occurs, and therefore where the
// ProjectReactor+Wingtips magic occurs. It should take the tracing state on the current thread here
// when block() is called, and propagate it into the Mono execution.
Pair<Long, Span> result = asyncThreadAndTraceId.block();
// then
// The thread in the Mono.map(...) should always be different than our main thread
// thanks to the publishOn(...).
assertThat(result.getLeft()).isNotEqualTo(mainThreadId);
// If expectTracingToPropagate is true, then we expect the span in the Mono.map(...) to match the root span.
// Otherwise, the current span when Mono.map(...) executed should be null.
if (expectTracingToPropagate) {
assertThat(result.getRight()).isEqualTo(rootSpan);
}
else {
assertThat(result.getRight()).isNull();
}
Tracer.getInstance().completeRequestSpan();
} finally {
Schedulers.removeExecutorServiceDecorator(WingtipsReactorInitializer.WINGTIPS_SCHEDULER_KEY);
SpringApplication.exit(serverAppContext);
}
}
private static void exitApplication() {
ConfigurableApplicationContext ctx = new SpringApplicationBuilder(Application.class).web(WebApplicationType.NONE).run();
int exitCode = SpringApplication.exit(ctx, () -> {
// return the error code
return 0;
});
System.out.println("Exit Spring Boot");
System.exit(exitCode);
}