Order ExitCodeGenerators and return first non-zero exit code

See gh-30457
This commit is contained in:
dugenkui 2022-03-29 12:59:54 +08:00 committed by Andy Wilkinson
parent 245e602ae0
commit 6718b10fa9
3 changed files with 33 additions and 3 deletions

View File

@ -354,7 +354,8 @@ include::code:MyApplication[]
Also, the `ExitCodeGenerator` interface may be implemented by exceptions. Also, the `ExitCodeGenerator` interface may be implemented by exceptions.
When such an exception is encountered, Spring Boot returns the exit code provided by the implemented `getExitCode()` method. When such an exception is encountered, Spring Boot returns the exit code provided by the implemented `getExitCode()` method.
If several `ExitCodeGenerator` are registered in a `ExitCodeGenerators`, they can be called in a specific order by using `org.springframework.core.annotation.Order` annotation or by implementing `org.springframework.core.Ordered`,
and `ExitCodeGenerators#getExitCode()` will return the first non-zero value.
[[features.spring-application.admin]] [[features.spring-application.admin]]
=== Admin Features === Admin Features

View File

@ -21,14 +21,22 @@ import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.annotation.Order;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* Maintains a collection of {@link ExitCodeGenerator} instances and allows the final exit * Maintains a collection of {@link ExitCodeGenerator} instances and allows the final exit
* code to be calculated. * code to be calculated.
* *
* <p>If several {@code ExitCodeGenerator} are registered in {@code ExitCodeGenerators},
* they can be called in a specific order by using {@link Order @Order} or by implementing {@link Ordered},
* and {@link #getExitCode()} will return the first non-zero value.
*
* @author Dave Syer * @author Dave Syer
* @author Phillip Webb * @author Phillip Webb
* @author GenKui Du
* @see #getExitCode() * @see #getExitCode()
* @see ExitCodeGenerator * @see ExitCodeGenerator
*/ */
@ -84,15 +92,17 @@ class ExitCodeGenerators implements Iterable<ExitCodeGenerator> {
*/ */
int getExitCode() { int getExitCode() {
int exitCode = 0; int exitCode = 0;
AnnotationAwareOrderComparator.sort(this.generators);
for (ExitCodeGenerator generator : this.generators) { for (ExitCodeGenerator generator : this.generators) {
try { try {
int value = generator.getExitCode(); int value = generator.getExitCode();
if (value > 0 && value > exitCode || value < 0 && value < exitCode) { if (value != 0) {
exitCode = value; exitCode = value;
break;
} }
} }
catch (Exception ex) { catch (Exception ex) {
exitCode = (exitCode != 0) ? exitCode : 1; exitCode = 1;
ex.printStackTrace(); ex.printStackTrace();
} }
} }

View File

@ -20,11 +20,13 @@ import java.io.IOException;
import java.util.List; import java.util.List;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.core.Ordered;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.withSettings;
/** /**
* Tests for {@link ExitCodeGenerators}. * Tests for {@link ExitCodeGenerators}.
@ -89,12 +91,29 @@ class ExitCodeGeneratorsTests {
assertThat(generators.getExitCode()).isEqualTo(2); assertThat(generators.getExitCode()).isEqualTo(2);
} }
@Test
void getExitCodeWithOrderedGenerator() {
ExitCodeGenerators generators = new ExitCodeGenerators();
generators.add(mockGenerator(0, 1));
generators.add(mockGenerator(1, 3));
generators.add(mockGenerator(2, 2));
generators.add(mockGenerator(3, 4));
assertThat(generators.getExitCode()).isEqualTo(2);
}
private ExitCodeGenerator mockGenerator(int exitCode) { private ExitCodeGenerator mockGenerator(int exitCode) {
ExitCodeGenerator generator = mock(ExitCodeGenerator.class); ExitCodeGenerator generator = mock(ExitCodeGenerator.class);
given(generator.getExitCode()).willReturn(exitCode); given(generator.getExitCode()).willReturn(exitCode);
return generator; return generator;
} }
private ExitCodeGenerator mockGenerator(int exitCode, int orderValue) {
ExitCodeGenerator generator = mock(ExitCodeGenerator.class, withSettings().extraInterfaces(Ordered.class));
given(generator.getExitCode()).willReturn(exitCode);
given(((Ordered) generator).getOrder()).willReturn(orderValue);
return generator;
}
private ExitCodeExceptionMapper mockMapper(Class<?> exceptionType, int exitCode) { private ExitCodeExceptionMapper mockMapper(Class<?> exceptionType, int exitCode) {
return (exception) -> { return (exception) -> {
if (exceptionType.isInstance(exception)) { if (exceptionType.isInstance(exception)) {