[스프링 부트] chapter 7. 스프링 부트 활용

스프링 부트 활용

스프링 부트에서는 어떻게 jar파일 하나로 실행이 가능할까?

mvn package를 하면 실행 가능한 jar파일 하나 생성됨.

기본적으로 자바에는 내장 jar를 로딩하는 표준적인 방법이 없음.

org.springframework.boot.loader.jar.JarFile을 사용하여 내장 jar들을 읽고,

org.springframework.boot.loader.Launcher를 사용하여 실행함으로써 jar파일 하나로 내부 jar들이 실행 가능해짐.

SpringApplication

아래와 같이 static하게 사용하는 경우 커스터마이징이 어려움

SpringApplication.run(Application.class, args);

객체로 선언하여 사용하면 커스터마이징이 용이함

SpringApplication application = new SpringApplication(Application.class);
app.run(args);

스프링부트의 기본적인 로그레벨은 INFO

변경하려면 VM Option에서는 -Ddebug를 주거나

Program arguments에 –debug를 주면 된다.

Failure Analyzer

애플리케이션 오류 발생시 에러메시지를 보여주는 템플릿이라 보면 됨.

여기 설정을 변경하면 에러 메시지를 원하는 형태로 보여줄 수 있게 됨. (거의 쓸일 없음)

https://docs.spring.io/spring-boot/docs/2.0.4.RELEASE/reference/htmlsingle/#boot-features-startup-failure

배너

최초 기동시 나오는 이미지

텍스트형태 배너의 경우 classpath에 banner.txt를 생성하면 최초 기동시 보여지게 됨.

이미지형태 배너의 경우 gif,jpg,png 확장자를 지원하며 application.properties에 배너 관련 프로퍼티를 추가

(resources하위에 생성하면 됨)

https://docs.spring.io/spring-boot/docs/2.0.4.RELEASE/reference/htmlsingle/#boot-features-banner

참고사항

SpringApplication에서도 setBanner()를 통해 배너 추가 가능

SpringApplication application = new SpringApplication(Application.class);
application.setBanner(new Banner() {
    @Override
    public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {
    out.println("==============================");
    out.println("Juho Kim");
    out.println("==============================");
});
application.run(args);

람다식으로 변경하면 아래와 같음

SpringApplication application = new SpringApplication(Application.class);
application.setBanner((environment, sourceClass, out) -> {
    out.println("==============================");
    out.println("Juho Kim");
    out.println("==============================");
});
application.run(args);

배너를 끄려면 아래와 같은 로직 추가

application.setBannerMode(Banner.Mode.OFF);

https://docs.spring.io/spring-boot/docs/2.0.4.RELEASE/reference/htmlsingle/#boot-features-customizing-spring-application

SpringApplicationBuilder를 이용하여 빌더 패턴으로 사용 가능

public static void main(String[] args) {
    new SpringApplicationBuilder()
        .sources(Application.class)
        .run(args);
}

https://docs.spring.io/spring-boot/docs/2.0.4.RELEASE/reference/htmlsingle/#boot-features-fluent-builder-api

ApplicationEvent

ApplicationListener를 통해 ApplicationEvent를 줄 수 있다.

애플리케이션이 최초 구동할 때 라던지,

애플리케이션이 구동된 후 라던지 등등

아래의 예제는 최초 구동할 때 실행되는 이벤트이다.

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

위 단계는 ApplicationContext가 생성되기 전에 실행되므로 Bean으로 등록하여 사용할 수 없다.

따라서 SpringApplication에 리스너를 등록하여 사용하는 방법으로 구현한다.

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

이벤트를 ApplicationStartedEvent로 선언한다면, ApplicationContext가 생성 된 후이므로

Bean으로 등록하여 처리해도 된다.

@Component
public class SampleListener implements ApplicationListener<ApplicationStartingEvent> {
    
    @Override
    public void onApplicationEvent(ApplicationStartingEvent applicationStartingEvent) {
        System.out.println("==========================");
        System.out.println("Application is starting");
        System.out.println("==========================");
    }
}
public static void main(String[] args) {
    SpringApplication application = new SpringApplication(Application.class);
    application.run(args);
}

https://docs.spring.io/spring-boot/docs/2.0.4.RELEASE/reference/htmlsingle/#boot-features-application-events-and-listeners

WebApplicationType

application.setWebApplicationType(WebApplicationType);

WebApplicationType.SERVLET : 웹으로 구현했을 경우

WebApplicationType.REACTIVE : WebFlux로 구현했을 경우

(둘다 구현되어 있고 별도로 위와 같이 선언하지 않는다면

디폴트는 SERVLET으로 생성된다. 디폴트값이 SERVLET을 먼저 찾도록 되어 있다.

따라서 REACTIVE만 사용해야 할 경우 명시적으로 선언해야 한다.)

애플리케이션 아규먼트 사용하기

Programe arguments에 --test 와 같이 작성한 후

ApplicationArguments를 인자값으로 받는 생성자를 선언한다면

Program arguments에 선언한 프로퍼티를 가져올 수 있다.

@Component
public class SampleArguments {
    
    public SampleArguments(ApplicationArguments arguments) {
        System.out.println("test: " + arguments.containsOption("test"));
    }
}

애플리케이션 실행 후 다른 무언가 실행하고 싶을 때

ApplicationRunner 또는 CommandLineRunner

@Component
public class SampleArguments implements ApplicationRunner {
    
    @Override
    public void run(ApplicationArguments args) {
        System.out.println("test: " + arguments.containsOption("test"));
    }
}
@Component
public class SampleArguments implements CommandLineRunner {
    
    @Override
    public void run(String... args) {
        Arrays.stream(args).foreach(System.out::println);
    }
}

이밖에도 ApplicationRunner가 여러개 일 경우 우선 순위를 정할 수 있다.

숫자가 작을 수록 우선순위가 더 높다.

@Component
@Order(1)
public class SampleArguments implements ApplicationRunner {
   ...
}