SpringApplication #2

학습 목표

  • Application Event Listner
  • Web Application Type
  • Application Argument
  • Application 실행한 뒤, 무언가를 추가로 실행하고 싶을 때

Application Event Listner

springboot는 Application Event Listner 를 통해
Application 실행 중 특정 이벤트가 발생 했을 때
어떻게 처리할 것인지 정의할 수 있다.

이 때,
Application Event Listner 는 Application이 실행되고 나서
Application Context가 만들어지기 전, 후 시점이 중요한 기점이 된다.

Application Event Listner는 Bean으로 등록하면 Application 클래스에서
따로 추가 설정 코드 없이 자동으로 springboot가 호출 해준다.

하지만, 예외 상황이 있다.
Application Event Listner의 이벤트 발생 시점이 Application Context가
만들어지기 전의 시점이라면 Bean으로 등록해도 해당 이벤트 시점에 springboot가
Listener를 알아서 호출해주지 않는다.

때문에 이러한 시점에 대한 Event Listner는 Application 클래스에서
addListener()로 직접 추가 해줘야 한다.

Application Context가 만들어지기 전

: ApplicationStartingEvent
: Listener 직접 등록.

SampleListener.java

public class SampleListener implements ApplicationListener<ApplicationStartingEvent> {
    @Override
    public void onApplicationEvent(ApplicationStartingEvent applicationStartingEvent) {
        System.out.println("=================================");
        System.out.println("Application is starting");
        System.out.println("=================================");
    }
}

Application.java

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(Application.class);
        app.addListeners(new SampleListener());

        app.run(args);
    }
}

예제의 ApplicationStartingEvent 시점은 Application Context가 만들어지기 전의 시점이고
이 때는 Listner를 Bean으로 등록하여 사용하려 할 경우,
해당 시점에 해당 Listner가 호출 되지 않는다.

Application Context가 만들어진 후

: ApplicationStartedEvent
: Listener Bean 등록.

SampleListener.java

@Component
public class SampleListener implements ApplicationListener<ApplicationStartedEvent> {
    @Override
    public void onApplicationEvent(ApplicationStartedEvent applicationStartedEvent) {
        System.out.println("=================================");
        System.out.println("Application is starting");
        System.out.println("=================================");
    }
}

Application.java

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Application 실행 완료 후 끝에 출력 되는 것을 볼 수 있다.

Web Application Type

  • NONE
  • REACTIVE
  • SERVLET

Spring WEB MVC 의존성을 가지는 프로젝트라면,
Web Application Type은 기본적으로 SERVLET으로 지정된다.

spring web flux 의존성을 가지고 서블릿이 없는 프로젝트라면,
Web Application Type은 기본적으로 REACTIVE으로 지정된다.

spring web flux 의존성을 가지지도 않고, 서블릿도 없는 프로젝트라면,
Web Application Type은 기본적으로 NONE으로 지정된다.

그렇다면,
Spring WEB MVC 의존성도 가지고, spring web flux 의존성도 가진다면
Web Application Type은 무엇으로 지정될까?

정답은 SERVLET으로 지정된다.

Spring WEB MVC 의존성도 가지고, spring web flux 의존성도 가지고 있는데
Web Application Type을 REACTIVE로 지정하고 싶다면?
Application.setWebApplicationType()을 통해서 바꿔주면 된다.

ex. setWebApplicationType()

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(Application.class);
        app.setWebApplicationType(WebApplicationType.SERVLET);  // 그 외 : REACTIVE, NONE
        app.run(args);

    }
}

Application Argument

  • JVM argument
    • '-D'로 시작한다.
    • JVM confing에 관련된 argument다.
    • ex. java -jar -Dpopo spring-application2.jar
  • Application argument
    • '--'로 시작한다.
    • Application Config에 관련된 argument다.
    • ex. java -jar --square spring-application2.jar

ex.

SampleArgument 라는 클래스를 만들고, Bean으로 등록한다.

해당 Bean을 통해

  • IDE 상에서의 Application 실행과
  • 배포된 jar로 Console 상에서 Application 실행

두 가지 상황으로 나누어 결과를 살펴 본다.

  • ※ 참고 ※ : ApplicationArgument를 매개변수로 가지는, 생성자가 단 하나인 Bean은
    springboot가 Application을 실행할 때 알아서 주입해준다.

SimpleArgument.java

@Component
public class SimpleArgument {
    public SimpleArgument(ApplicationArguments arguments) {
        System.out.println("popo : " + arguments.containsOption("popo"));
        System.out.println("square : " + arguments.containsOption("square"));
    }
}

Application.java

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

IDE 상에서의 Application 실행

Console 상에서 Application 실행

두 가지 결과 해석

: 두 가지 결과 모두 JVM option argument인 -Dpopo는 포함하지 않아
false를 반환함을 알 수 있다.

즉, 매개변수였던 ApplicationArgument는 JVM argument에 대한 정보를 갖지 않는다.

Application 실행한 뒤,
무언가를 추가로 실행하고 싶을 때

  • ApplicationRunner(추천 방식)
  • CommandLineRunner

ex. ApplicationRunner

SimpleAfterApplication.java

@Component
public class SimpleAfterApplication implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("SimpleAfterApplication1 - popo : " + args.containsOption("popo"));
        System.out.println("SimpleAfterApplication1 - square : " + args.containsOption("square"));
    }
}

Application.java

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Application이 실행되고 난 뒤에 SimpleAfterApplication이
실행되는 것을 볼 수 있다.
또한, JVM argument 에 대해서는 받지 못한다.

ex. CommandLineRunner

SimpleAfterApplication2.java

@Component
public class SimpleAfterApplication2 implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        System.out.println("\nSimpleAfterApplication2");
        Arrays.stream(args).forEach(System.out::println);
    }
}

Application.java

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

ApplicationRunner와 같은 결과로,
Application이 실행되고 난 뒤에 SimpleAfterApplication이
실행되는 것을 볼 수 있다.
또한, JVM argument 에 대해서는 받지 못한다.

같은 결과임에도 ApplicationRunner가 추천되는 이유는 CommandLineRunner는
조금 사용하기에 무식하게 구현되어 있고 ApplicationRunner가 쓰기 편하게 구현되어 있다.

@Order Annotaion

: 추가로 실행할 것이 여러 개일 때, @Order로 실행 순서를 지정할 수 있다.

바로 위 예제에서 만든
'SimpleAfterApplication' 클래스와 'SimpleAfterApplication2' 클래스 2개를
Bean으로 등록하여 순서 지정 없이 Application으로 실행 해보면
아래와 같은 결과를 보인다.

@Order로
'SimpleAfterApplication2' 클래스에 1순위를 주고,
'SimpleAfterApplication2' 클래스에 2순위를 주게 되면?

@Component
@Order(1)
public class SimpleAfterApplication2 implements CommandLineRunner {
	...
}
@Component
@Order(2)
public class SimpleAfterApplication implements ApplicationRunner {
	...
}

'SimpleAfterApplication2' Bean이 먼저 실행 된 것을 볼 수 있다.

좋은 웹페이지 즐겨찾기