Skip to content

Commit b9be826

Browse files
committed
Optionally close context after command logic
- spring.shell.context.close=true adds ApplicationListerner which attempts to close context with ApplicationReadyEvent. - Backport #863 - Relates #866
1 parent 17b7321 commit b9be826

File tree

4 files changed

+88
-1
lines changed

4 files changed

+88
-1
lines changed

spring-shell-autoconfigure/src/main/java/org/springframework/shell/boot/ApplicationRunnerAutoConfiguration.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2021 the original author or authors.
2+
* Copyright 2021-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,7 +19,10 @@
1919

2020
import org.springframework.boot.autoconfigure.AutoConfiguration;
2121
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
22+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
23+
import org.springframework.boot.context.event.ApplicationReadyEvent;
2224
import org.springframework.boot.context.properties.EnableConfigurationProperties;
25+
import org.springframework.context.ApplicationListener;
2326
import org.springframework.context.annotation.Bean;
2427
import org.springframework.shell.DefaultShellApplicationRunner;
2528
import org.springframework.shell.ShellApplicationRunner;
@@ -34,4 +37,20 @@ public class ApplicationRunnerAutoConfiguration {
3437
public DefaultShellApplicationRunner defaultShellApplicationRunner(List<ShellRunner> shellRunners) {
3538
return new DefaultShellApplicationRunner(shellRunners);
3639
}
40+
41+
@Bean
42+
@ConditionalOnProperty(prefix = "spring.shell.context", name = "close", havingValue = "true")
43+
public ApplicationReadyEventListener applicationReadyEventListener() {
44+
return new ApplicationReadyEventListener();
45+
}
46+
47+
static class ApplicationReadyEventListener implements ApplicationListener<ApplicationReadyEvent>{
48+
49+
@Override
50+
public void onApplicationEvent(ApplicationReadyEvent event) {
51+
// request context close after application runners so that
52+
// shell exits in case that context is kept alive
53+
event.getApplicationContext().close();
54+
}
55+
}
3756
}

spring-shell-autoconfigure/src/main/java/org/springframework/shell/boot/SpringShellProperties.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public class SpringShellProperties {
3434
private Command command = new Command();
3535
private Help help = new Help();
3636
private Option option = new Option();
37+
private Context context = new Context();
3738

3839
public void setConfig(Config config) {
3940
this.config = config;
@@ -107,6 +108,14 @@ public void setOption(Option option) {
107108
this.option = option;
108109
}
109110

111+
public Context getContext() {
112+
return context;
113+
}
114+
115+
public void setContext(Context context) {
116+
this.context = context;
117+
}
118+
110119
public static class Config {
111120

112121
private String env;
@@ -603,6 +612,19 @@ public void setCaseType(OptionNamingCase caseType) {
603612
}
604613
}
605614

615+
public static class Context {
616+
617+
private boolean close = false;
618+
619+
public boolean isClose() {
620+
return close;
621+
}
622+
623+
public void setClose(boolean close) {
624+
this.close = close;
625+
}
626+
}
627+
606628
public static enum OptionNamingCase {
607629
NOOP,
608630
CAMEL,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.shell.boot;
17+
18+
import org.junit.jupiter.api.Test;
19+
20+
import org.springframework.boot.autoconfigure.AutoConfigurations;
21+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
22+
23+
import static org.assertj.core.api.Assertions.assertThat;
24+
25+
public class ApplicationRunnerAutoConfigurationTests {
26+
27+
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
28+
.withConfiguration(AutoConfigurations.of(ApplicationRunnerAutoConfiguration.class));
29+
30+
@Test
31+
void contextCloseDisabledByDefault() {
32+
contextRunner.run(context -> assertThat(context)
33+
.doesNotHaveBean(ApplicationRunnerAutoConfiguration.ApplicationReadyEventListener.class));
34+
}
35+
36+
@Test
37+
void contextCloseEnabled() {
38+
contextRunner.withPropertyValues("spring.shell.context.close:true")
39+
.run(context -> assertThat(context)
40+
.hasSingleBean(ApplicationRunnerAutoConfiguration.ApplicationReadyEventListener.class));
41+
}
42+
43+
}

spring-shell-autoconfigure/src/test/java/org/springframework/shell/boot/SpringShellPropertiesTests.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ public void defaultNoPropertiesSet() {
7070
assertThat(properties.getHelp().getLongNames()).containsExactly("help");
7171
assertThat(properties.getHelp().getShortNames()).containsExactly('h');
7272
assertThat(properties.getOption().getNaming().getCaseType()).isEqualTo(OptionNamingCase.NOOP);
73+
assertThat(properties.getContext().isClose()).isFalse();
7374
});
7475
}
7576

@@ -112,6 +113,7 @@ public void setProperties() {
112113
.withPropertyValues("spring.shell.help.long-names=fake")
113114
.withPropertyValues("spring.shell.help.short-names=f")
114115
.withPropertyValues("spring.shell.option.naming.case-type=camel")
116+
.withPropertyValues("spring.shell.context.close=true")
115117
.withUserConfiguration(Config1.class)
116118
.run((context) -> {
117119
SpringShellProperties properties = context.getBean(SpringShellProperties.class);
@@ -151,6 +153,7 @@ public void setProperties() {
151153
assertThat(properties.getHelp().getLongNames()).containsExactly("fake");
152154
assertThat(properties.getHelp().getShortNames()).containsExactly('f');
153155
assertThat(properties.getOption().getNaming().getCaseType()).isEqualTo(OptionNamingCase.CAMEL);
156+
assertThat(properties.getContext().isClose()).isTrue();
154157
});
155158
}
156159

0 commit comments

Comments
 (0)