[인프런 강의] 스프링 부트 개념과 활용 - 3

2020. 5. 27. 13:44강의/스프링 부트 개념과 활용

지난 정리까지는 스프링 부트의 주요 작동 원리에 대해서 공부했다면,

이 다음부터는 스프링 부트의 핵심 기능들에 대해 공부할 예정이다.

또한 스프링 웹 MVC, 스프링 데이터, 스프링 시큐리티 등의 

각종 기술을 연동 하는 방법에 대해서도 공부할 예정이다.

 

1.  로그와 배너

지난시간까지 애플리케이션을 실행시키는 코드는

SpringApplication의 static메소드 run을 바로 이용하는 방법이었다. 

하지만 여러가지 기능을 사용하기 위해서는 SpringApplication 객체를 만들어 사용하는 것이 좋다.

이렇게 해서 실행하면 기본적으로 INFO레벨의 로그가 뜨는 것을 확인할 수 있다. 이때 Debug 로그를 찍을 수 있는 방법에 대해 먼저 정리하고 넘어 가겠다. 디버그 로그를 찍으면 좋은 점은 어떠한 자동설정이 적용이 되었는지, 적용되지 않은 자동설정이 있다면 그 이유까지 함께 나타내 주기 때문에 이와같은 정보를 알고자 할 때는 디버그 로그를 찍게끔 설정하는 것이 좋겠다.

인텔리제이의 우상단에 보면 위와 같은 모습을 볼 수 있다. Edit Configurations에 들어가서 VMoption에 -Ddebug를 적고 적용시켜 준 다음 애플리케이션을 실행해보면 디버그 로그가 찍히는 것을 확인할 수 있을것이다.

 

*스프링 부트를 사용하다보면 에러가 기존의 에러 로그보다 이쁜(?) 템플릿으로 찍히는 것을 확인할 수 있다. 이것은 FailureAnalyzer라는 것 덕분인데, 스프링 부트는 여러 FailureAnalyzer가 자동으로 설정되어 있다고 한다.

 

*스프링 부트를 실행했을 때 나오는 배너를 바꾸는 방법도 있다. 

src/main/resource에 banner.txt 파일을 생성하고 원하는 모양의 배너를 텍스트로 만들어 주기만 하면 된다.

application.setBanner를 통해 배너설정도 할 수 있음

 

2. 이벤트 리스너

스프링부트는 여러가지 리스너를 구현하여 사용할 수 있다. 하지만 이벤트가 발생하는 시점은 각각 다르다. 예를들어 ApplicationStartingEvent같은 경우 애플리케이션 컨텍스트가 만들어 지기 전에 발생하는 이벤트인데, 이같은 경우에는 빈으로 등록하더라도 해당 이벤트가 발생했을때의 리스너가 동작하지 않는다. 

위와 같이 @Component 어노테이션을 통해 빈으로 등록하고 실행해 보아도 작성한 코드가 찍히지 않는다. 이것은 이벤트의 발생 시점 때문이다. 이럴때는 SpringApplication 객체에 직접 리스너를 등록해 주어야한다.

위와 같이 addListners메소드로 직접 등록해주기 때문에, 해당 리스너 클래스는 빈으로 등록할 필요가 없다.

 

반면에, ApplicationContext가 생성되고 나서 발생하는 이벤트의 리스너 같은경우에는 빈으로 등록만 해주면 따로 설정하지 않아도 리스너가 동작하게 된다. 

< > 안을 보면 Strating에서 Started로 바뀐것을 볼 수 있다. 

ApplicationStartedEvent같은 경우 ApplicationContext가 생성된 이후에 발생하는 이벤트이므로 빈으로 등록만 해두면 적절한 시점에서 자동으로 리스너가 동작하게 된다. 따라서 SpringApplication 객체를 통해 addListners를 해줄 필요가 없다.

 

3. WebApplicationType 설정

application.setWebApplicationType을 해보면 3가지 모드가 있는 것을 알 수 있다.

SERVLET, REACTIVE, NONE이 그것인데, 차례대로 우선순위가 적용된다. 

이러 한 모드를 설정할 수 있게 하는 이유는, 만약에 이러한 설정을 할 수 없다면 서블릿과 웹플럭스(REACTIVE모드로 만드는)가 함께있을때 우선순위가 서블릿이므로 웹플럭스로 확인을 할 수가 없기때문이다. 

 

4. 외부설정

스프링 부트에 외부의 설정을 적용하는 가장 기본적인 방법은 resource밑에 application.properties라는 파일을 만드는 것이다. (이 이름은 다른 이름으로 대체되어 사용할 수 없다. 반드시 application.properties라고 이름 짓고 사용해야한다.)

이 파일에 키-밸류 형식으로 정의된 것을 프로젝트에서 사용할 수 있는 것이다.

위와 같이 minsub.name 이라는 키값에 minsub이라는 밸류값을 application.properties에 설정해주었다.

이것을 프로젝트에서 사용하는 가장 기본적인 방법은 @Value어노테이션을 통해 값을 가지고 오는 것이다.

위와 같이 application.properties에 설정한 값이 프로젝트에서 잘 사용되는 것을 볼 수 있다. 

 

하지만 스프링 부트에는 이렇게 외부 설정을 할 수 있는 properties의 종류가 매우 많아서 각각에 우선순위를 부여하고 있다. 위에서 만든 application.properties같은 경우 우선순위 15위에 위치한 파일이므로, 더 우선시 되어야 하는 properties파일이 매우 많다.

더 높은 우선순위(숫자가 낮은)의 프로퍼티는 낮은 우선순위의 프로퍼티를 오버라이드 하므로 우선순위가 높은 프로퍼티의 설정이 적용된다. 외울 수는 없겠지만 프로퍼티의 우선순위는 아래와 같다.

 

프로퍼티 우선 순위

  1. 유저 홈 디렉토리에 있는 spring-boot-dev-tools.properties
  2. 테스트에 있는 @TestPropertySource
  3. @SpringBootTest 애노테이션의 properties 애트리뷰트
  4. 커맨드 라인 아규먼트
  5. SPRING_APPLICATION_JSON (환경 변수 또는 시스템 프로티) 에 들어있는 프로퍼티
  6. ServletConfig 파라미터
  7. ServletContext 파라미터
  8. java:comp/env JNDI 애트리뷰트
  9. System.getProperties() 자바 시스템 프로퍼티
  10. OS 환경 변수
  11. RandomValuePropertySource
  12. JAR 밖에 있는 특정 프로파일용 application properties
  13. JAR 안에 있는 특정 프로파일용 application properties
  14. JAR 밖에 있는 application properties
  15. JAR 안에 있는 application properties
  16. @PropertySource
  17. 기본 프로퍼티 (SpringApplication.setDefaultProperties)

또한 외부 설정파일이 위치할 수 있는 곳이 네가지가 있는데, 이렇게 서로 다른 위치에 외부 설정파일을 위치 시키면 덮어쓰게 하지 않고 여러 외부 설정파일을 적용시킬 수 있다. 위치할 수 있는 네 곳은 아래와 같다. 

  1. file:./config/
  2. file:./
  3. classpath:/config/
  4. classpath:/

 

5. 클래스를 통해 외부설정값 사용

4번내용을 보면 외부에서 설정한 값을 @Value어노테이션을 통해 주입받아 사용하고 있다. 하지만 이것은 타입-세이프 하지 못하다. (오타가 나는 등의 사소한 문제로 인해 오류가 발생할 수 있다.) 이것을 @ConfigurationProperties 어노테이션을 이용하여 타입세이프티 하게 해줄 수 있을 뿐 아니라 여러 프로퍼티를 읽어 오고, 빈으로 등록할 수 있다. 역시 코드로 보아야 이해가 빠를 것 같다.

 

왼쪽이 프로덕션 코드의 application.properties이고 오른쪽이 전체 프로젝트폴더에 위치한 application.properties이다.

 

위와 같이 @ConfigurationProperties 어노테이션을 이용하면 외부설정들중 minsub이라는 키값을 통해 설정되는 값들을 모두 사용할 수 있다. 이때 각각 다른 설정파일에 있는 값들을 모두 사용할 수 있고, 중복된 값은 더 우선순위가 높은 설정파일의 값을 사용하는 것을 확인할 수 있었다.