= ``ExitCodeGenerator``에 관한 이야기
honeymon, <ihoneymon@gmail.com>
v0.0.1, 2018/03/12
:sb: 스프링 부트
:app: 애플리케이션

* link:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-application-exit[Application Exit - Spring Boot Reference Guide]

{app}이 정상적으로 종료되는 것은 꽤 중요하다. {app}의 갑작스런 죽음과는 달리 특정 상황이 발생했고 그 상황에 맞춰 종료코드를 반환하고 죽는다면 그에 대한 대응하기가 수월해진다. {sb}에서 장애대응을 수월하게 할 수 있도록 특정상황에 따른 종료코드(Exit Code)를 반환하며 {app}을 정상종료 시키는 기능을 제공한다.

{sb} 참고문서에 나온 예제는 다음과 같다.
[source,java]
----
@SpringBootApplication
public class ExitCodeApplication {
	@Bean
	public ExitCodeGenerator exitCodeGenerator() { 
		return () -> 42;
	}
	public static void main(String[] args) {
		System.exit(SpringApplication
				.exit(SpringApplication.run(ExitCodeApplication.class, args)));
	}
}
----

이와 관련된 것은 아래 두 가지다.

* ``ExitCodeGenerator``
* ``SpringApplication.exit(ApplicationContext context, ExitCodeGenerator... exitCodeGenerators)``

위 코드는 대략 다음과 같다.

.``ExitCodeGenerator``
[source,java]
----
@FunctionalInterface
public interface ExitCodeGenerator {
    /**
     * Returns the exit code that should be returned from the application.
     * @return the exit code.
     */
    int getExitCode();
}
----

.``SpringApplication.exit()`` 메서드
[source,java]
----
public static int exit(ApplicationContext context,
        ExitCodeGenerator... exitCodeGenerators) {
    Assert.notNull(context, "Context must not be null");
    int exitCode = 0;
    try {
        try {
            ExitCodeGenerators generators = new ExitCodeGenerators();
            Collection<ExitCodeGenerator> beans = context
                    .getBeansOfType(ExitCodeGenerator.class).values();
            generators.addAll(exitCodeGenerators);
            generators.addAll(beans);
            exitCode = generators.getExitCode();
            if (exitCode != 0) {  // <1>
                context.publishEvent(new ExitCodeEvent(context, exitCode));
            }
        }
        finally {
            close(context);
        }
    }
    catch (Exception ex) {
        ex.printStackTrace();
        exitCode = (exitCode == 0 ? 1 : exitCode);
    }
    return exitCode;
}
----
<1> ``exitCode != 0`` 조건이 만족하면 ``ExitCodeEvent`` 이벤트가 발생한다.

``ExitCodeGenerator`` 인터페이스를 ``SpringApplication.exit()`` 전달하면 ``SpringApplication.exit()``는 ``getExitCode()`` 메서드를 호출하여 종료코드를 받는다. 이 때 이 종료코드가 0인 경우에는 일반적인 애플리케이션 종료를 진행한다. 

[NOTE]
====
``0``이 아닌 경우에는 종료코드 발송 이벤트(``ExitCodeEvent``)가 발생한 후 애플리케이션이 종료된다.
====

애플리케이션에서 특정 예외발생 시 다음과 같은 형식으로 종료코드 반환 이벤트를 발생시키며 종료시킬 수 있겠다.

[source,java]
----
@Autowired
ExitCodeGenerator exitCodeGenerator;

try {
	// 예외가 발생할 수 있는 상황
} catch (WannabeException e) {
    // 특정조건의 예외가 발생하면 애플리케이션을 안전하게 종료시킬 수도 있겠다.
    // 
    SpringApplication.exit(applicationContext, exitCodeGenerator);
}
----

``WannabeException``에 대한 예외처리를 할 수 있는 ``@ControllerAdvice`` 클래스를 정의해서 ``WannabeException``가 발생하면 특정코드를 발생하며 종료되도록 하는 것도 가능하겠다.

[source,java]
----
@ControllerAdvice
class GlobalControllerExceptionHandler {
    @ExceptionHandler(WannabeException.class)
    public void handleConflict(WannabeException we) {
        // todo we
        SpringApplication.exit(applicationContext, () -> 810301);
    }
}
----