4. 스프링부트 AutoConfiguration
"스프링부트 백엔드 프로그래밍"이라는 주제로 약 8주간 글을 작성할 예정입니다. 스터디가 잘못된 방향으로 가지 않도록, 의견 및 조언을 아낌없이 해주시길 부탁드립니다.
지난번 글에서는, 스프링 프레임워크, 스프링부트의 기본 개념인 IoC, DI에 대해서 설명하였습니다. 이번 글에서는 AutoConfiguration에 대해서 가벼운(?) 마음으로 소개합니다.
1주차 - 스프링부트란 무엇인가?, 간단한 API 서버 만들어보기
2주차 - 스프링 프레임워크 기본 개념 이해하기
3. [이전글]스프링 프레임워크 IoC, DI(의존성주입)
4. [현재글]스프링부트 AutoConfiguration
3주차 - Rest API, 테스트 코드 작성하기, 예외 처리하기
5. Rest API (HTTP 기본 개념)
6. 테스트 코드 작성하기
7. 예외 처리하기
4주차 - 캐싱
8. 스프링 캐시 추상화
9. Redis 연동하기
5주차 - MQ, Pub/Sub
[미정] 6주차 - 보안(인증)
[미정] 7주차 - 병렬, 비동기 프로그래밍
[미정] 8주차 - Spring Cloud
[미정] JPA, Spring Data, Spring Session 등
또한, 시간 관계상 모든 내용을 정리하지 못하였습니다. 죄송하지만, 각자 알아서 나머지 공부를 하시길 바랄게요. 저 또한 열공해서 부족한 부분은 채워 넣겠습니다.
급하게 글을 작성하고 다시 읽어보니, 문맥상 이해하기 어려운 내용이 많네요.
ㅠㅠ 쉽게 설명하고 싶은데, 많이 어렵습니다...
그리고, 이번 글은 코드를 따라 하지 않아도 됩니다. 눈으로 보고 이해만 하셔도 됩니다.
스프링부트의 AutoConfiguration 은 가장 중요하면서도, 어려운 개념입니다. AutoConfiguration 는 스터디가 끝날 때까지 계속 등장하게 되는 단어입니다.
@EnableAutoConfiguration
이전 시간에서도 소개하였지만, 스프링부트에서는 @SpringBootApplication 어노테이션을 사용합니다.
맥북 기준으로는 command + 마우스 클릭 을 하면 됩니다. 윈도우는 잘 모르겠네요. 주요한 어노테이션이 정의가 되어있습니다.
@SpringBootApplication 어노테이션을 주석처리하고, 아래와 같이 수정해도 스프링부트 애플리케이션은 잘 실행이 될 것입니다.
그럼 @EnableAutoConfiguration 은 어떤 역할을 할까요?
스프링부트의 AutoConfiguration 기능을 사용하겠다는 설정입니다. 스프링부트 애플리케이션을 처음 시작하면, @SpringBootApplication 어노테이션이 선언이 되어있고, 해당 어노테이션에서 @EnableAutoConfiguration 이 정의되어있기 때문에, 스프링부트를 실행하면 자연스럽게 AutoConfiguration 이 동작할 것입니다. 우리는 스터디 1주차에서 스프링 부트 스타터 웹 의존성을 추가하면, 자동으로 임베디드 톰캣 서버가 실행이 되는 것을 확인하였습니다. 그리고, 톰캣 관련 AutoConfiguration 이 동작했기 때문이라고 설명하였습니다.
spring-boot-autoconfigure 패키지에 AutoConfiguration 을 해야 하는 목록을 전부 정의가 되어있습니다.
아래 github 에서도 확인할 수 있습니다.
임베디드 톰캣을 시작하는 클래스는 바로 아래와 같습니다.
모든 클래스에는 @Configuration 이 정의가 되어있습니다. 세어보진 않았지만, 대략 수십개가 넘습니다... 하지만, 이 수많은 리스트를 전부 수행하지는 않습니다. 각 조건에 맞아야 수행합니다.
AutoConfiguration 예시 1) 임베디드 톰캣
스프링부트 웹 서버를 실행하면 아래와 같이 임베디드 톰캣이 8080 포트로 실행됩니다.
임베디드 톰캣 서버에 대한 AutoConfiguration 의 수행은 EmbeddedWebServerFactoryCustomizerAutoConfiguration 에 정의되어있습니다. 그리고, @ConditionalOnClass 라고 정의가 되어있네요.
@CondionalOnClass 에 Tomcat.class 가 설정이 되어있는데요. 이건, 애플리케이션에 클래스 패스에 Tomcat.class 가 있다면 AutoConfiguration 을 수행하라는 의미입니다.
즉, gradle 또는 maven 의존성에 톰캣이 있다면, 해당 로직은 수행할 것입니다.
반면에, 같은 클래스에 UnderTow 라는 임베디드 서버에 대한 설정도 있습니다만, 빨간색으로 표시가 되네요. 아마 UnderTow 라는 의존성은 없는 것 같습니다. 그래서, UnderTow 에 대한 AutoConfiguration 은 실행되지 않습니다.
만약, Undertow 에 대한 AutoConfiguration 을 실행하고 싶다면 어떻게 할까요? 의존성을 추가해주면 됩니다. tomcat 을 제외시키고, undertow 를 추가해주겠습니다. tomcat 의존성은 spring-boot-starter-web 에 기본으로 추가되는 의존성이라서, 아래와 같이 명시적으로 제외를 시켜줘야 합니다.
자, 아래와 같이 Undertow 서버로 실행하였습니다.
어쨋든, 중요한 사실은, 스프링부트는 의존성에 따라서 자동으로 AutoCOnfiguration 을 구성해 준다는 사실입니다. 또한 여기서 한가지 더 중요한 사실이 있습니다.
1주차에서 임베디드 톰캣 서버의 포트를 변경한 것을 기억하시나요.
임베디드 톰캣 서버가 아니라, Undertow 서버로 변경한 경우에는 어떻게 될까요? 마찬가지로 변경된 8081 포트로 잘 동작합니다.
Undertow 의 경우에도 동일하게 포트가 변경되었습니다. 즉, 속성 설정은 톰캣을 사용하던, Undertow 를 사용하던 변함이 없습니다. 단, 의존성에 따라서 어떤 임베디드 서버에서 동작하는지만 변경될 뿐이죠. 이 개념은 스프링의 추상화 전략 때문이빈다. 앞으로 스터디를 진행하면서, 추상화 전략에 대해서도 많은 얘기를 나누게 될 것입니다. 스프링부트의 전략이라기 보다는, 스프링의 기본 철학입니다. 물론, 모든 속성이 추상화 되어있지는 않습니다. 톰캣 서버의 쓰레드 풀 설정의 경우에는 아래와 같이 수정해야 합니다.
AutoConfiguration 예시 2) H2 Console
의존성이 있어도, 특정 조건에 한해서 AutoConfiguration 수행하도록 설정이 된 경우도 있습니다. 예를 들어서, 개발 시 h2 데이터베이스를 자주 사용하게 되는데요.
h2 는 콘솔을 제공해줍니다. 근데, 의존성이 있다고 무조건 h2 Console 에 대한 기능에 대해서 AutoConfiguration 을 수행할까요? 그렇지 않습니다. 아래 샘플 코드를 봐주세요.
spring.h2.console.enabled 값이 true 로 정의한 경우에만 동작합니다. 참고로, baeldung 글을 참고하였습니다.
https://www.baeldung.com/spring-boot-h2-database
사실, 스프링부트가 더 어려운 이유는... 스프링 부트의 버전이 변경될 때마다, 이런 설정이 자주 바뀐다는 사실입니다. 그래서, 우리는 스프링부트 의 릴리스 노트를 유심히 지켜봐야 합니다. 아무 생각없이 스프링부트의 버전을 올렸을 때 큰 낭패를 당할 수 있습니다.
AutoConfiguration 예시 3) Spring Data JPA
의존성만 추가하고, 애플리케이션을 실행해보겠습니다.
오류가 발생합니다.
임베디드 톰캣서버는 아무 설정 안해도 잘 되었잖아요.. 설정 안했는데 잘 돼었잖아요.. 이건 왜 안되요...
스프링 데이터 JPA 의존성을 추가하면, 반드시 아래와 같이 url 을 입력해줘야 해요.
위와 같이 AutoConfiguration 에 기본적으로 필수로 필요한 설정 값을 추가하면 자동으로 DataSource 객체를 만들어줄 것입니다. 즉, 아무 소스코드를 작성하지 않아도 데이터베이스 연동이 됩니다. 참 편합니다. 스프링부트가 도입되기 전에는 아래와 같이 정의를 했었다고 하네요.. 라뗴는..
스프링부트가 도입된 이후에, AutoConfiguration 기능에 의해서, 의존성이 필요한 객체를 자동으로 Bean 으로 등록해주기 때문에 매우 심플하게 좋습니다. 개발자는 비즈니스 로직에만 집중할 수 있게 되거든요.. 하지만 무조건 좋은건 아니랍니다..
DataSOurce 를 만드는 AutoConfiguration 구문은 아래와 같습니다. 보시면, ConditionalOnMissingBean 이 선언되어있습니다. DataSource 가 없는 경우에만 수행한다는 조건입니다.
만약에, 애플리케이션에서 DataSource 객체를 개발자가 따로 정의하였다면, 위 구문은 실행이 되지 않을 것입니다. 스프링부트의 AutoConfiguration 에 의해서 DataSource 객체가 생성되지 않습니다.
스프링부트 애플리케이션에서는, 스프링부트가 자동으로 생성해주는 dataSource 를 사용하지 않고, 개발자가 정의한 mySqlDataSource 라는 빈 객체를 사용하게 될 것입니다.
그렇다면,
스프링부트에서 자동으로 생성해주는 dataSource 를 사용하는게 좋을까요?
아니면 따로 dataSource 를 정의해서 사용하는게 좋을까요?
정답은 없습니다. 필요에 따라서 만들던, 만들지 않던 선택하면 됩니다. 단, 커스텀하게 Bean 을 생성하게 되는 경우에는, 코드에 대한 확신이 있어야 합니다. 내가 작성한 mySqlDataSource 는 제대로 동작할 것인가? 스프링 최고 전문가들이 개발한 AutoConfiguration 에 의해 생성한 코드가 더 신뢰성이 있지 않을까?
하지만, 커스텀하게 되는 경우도 꽤 많습니다. 다른 예를 들어볼게요...
AutoConfiguration 예시 4) Spring Cache
우리는 스터디 4주차에서, 캐싱에 대해서 상세하게 다룰 예정입니다. 캐시 저장소를 사용하기 위해서 spring-data-redis 레디스 의존성을 추가해볼게요.
스프링 캐시 추상화를 사용하기 위해서 아래와 같이 @EnableCaching 를 선언해봅니다.
자, 그리고 캐싱을 적용할 곳에 @Cacheable 어노테이션을 사용해봅니다.
레디스 콘솔에서 데이터가 잘 저장이 되었는지 확인해봅시다.
우리는 별도의 코드를 작성하지 않았습니다. 스프링부트의 AutoConfiguration 에 의해서 CacheManager 객체가 자동으로 생성이 되었고, CacheManager 에 의해서 캐싱 기능이 잘 동작하였습니다. 하지만, 기본 설정이 아닌, 커스텀하게 변경하고 싶다면 어떻게 하면 될까요?
네 맞습니다. CacheManager 를 개발자가 직접 정의해주면 됩니다. 단, 확신을 갖고... 자세한 내용은 4주차 캐싱을 스터디하면서 다시 얘기하겠습니다.
마무리
이번 글에서는 AutoConfiguration 에 대해서 알아봤습니다. 어떻게 설명하면 재미있을까 고민했지만... 재미는 없네요. 조금이라도 도움이 되셨기를 바랍니다.
1. 임베디드 톰캣의 쓰레드 풀 사이즈를 변경해보세요.
(성능 테스트까진 안해도 됨. 대충 어떻게 하는지 이해만 하시면 됩니다. )
2. 샘플 소스에서는 영화 검색 API 를 사용했는데요. 응답 데이터 필드가 누락되어있습니다. 데이터를 전부 가져올 수 있도록 필드를 추가해주세요.
3. 영화 외 다른 검색 서비스를 추가로 연동해보세요. 아무거나 하나만.. 자유롭게!!
4. 영화 검색 시 평점이 0 인 데이터는 제외하는 기능을 개발해주세요.
5. API 디자인 지침이라는 글을 읽어주세요. 단, 전부 읽지는 마시고 "REST 소개, 리소스 중심으로 API 구성, HTTP 메서드를 기준으로 작업 정의" 까지 읽어주셔도 됩니다.
https://docs.microsoft.com/ko-kr/azure/architecture/best-practices/api-design
공통(중요) - 선택 과제이지만, 가능하시면 꼭 해보세요!! 매우 중요한 내용입니다.
1. 영화 평점 순 정렬에 대한 단위 테스트를 작성해주세요. 평점이 높은 순으로 정렬이 잘 되는지 검증하면 됩니다.
2. 영화 검색 시 평점이 0 인 데이터를 제외하는 기능에 대해서 단위테스트를 작성해주세요.
(단위테스트는 @SpringBootTest 사용하지 않고 작성해보기)
어렵다는 의견이 많아서.. 참고할 수 있게 글을 작성했습니다. 아래 내용 보세요
https://brunch.co.kr/@springboot/536
3. 네이버 오픈 API의 인증이 실패한 경우에 대해서, 예외 처리 코드를 작성해주세요. 예외 발생 시 커스텀하게 정의한 Json 포맷으로 응답하도록 개선해주세요.
아래 선택과제는 정말 시간 되시는 분만..
스터디 끝까지 RestTemplate 를 계속 사용하실 분
1. 영화 검색 및 그외 다른 검색... 2개 이상의 검색 기능에 사용하는 로직에서, RestTemplate 를 공통으로 사용하는 부분이 있다면, 중복코드가 없도록 리팩토링 해주세요.
2. RestTemplate Bean 설정 컨피그 클래스에서 매직넘버로 설정한 셋팅 값들 전부 application.properties 또는 application.yml 파일로 속성 분리하기.
RestTemplate 를 사용하지 않고 다른 방법으로 개발하실 분
1. FeignClient 를 사용하도록 변경해보기. 구글링해서 찾아보시면 됩니다.
(feignClient 를 직접 사용해도 되고, 아니면 spring cloud openfeign 을 사용하셔도 됩니다.)