여러분 봄이 왔습니다!!
하핫.. 사실은 글을 쓰는 현재는 12월 몹시 추운 날입니다. 롱패딩까지 입고있다구요…
하지만! 저희의 프로젝트에는 봄이 왔습니다! 드디어 Spring의 기능을 써볼 예정인데요. 바로 제목에 나와있는 @Configuration입니다.
저희는 이전글에서 눈빠지게 설정파일을 만들었는데 무슨 또 설정을 하라는거냐!!! 하시겠죠? 하지만 우리가 만든 AppConfig라는 세팅파일을 Spring이 관리해줄 수 있도록 설정해주는 과정을 배우는것이라 우리는 우리 프로젝트를 관리해야하는 짐을 스프링에게 좀 덜어낼 수 있을겁니다.
직접 한번 해보러 가봅시다!!
@Configuration
아마 @를 보시고 눈치가 좋으신 분들은 이게 Annotation인줄 이미 아셨을 수도 있을겁니다. 맞습니다! 이녀석은 Annotation입니다. Annotation이 무엇인지 모르시다면 아쉽게도 저희 블로그에는 정리한 글이 없기 때문에 한번 구글 검색을 해보시고 오시면 좋을것같아요~
이 @Configuration은 우리가 지난시간에 소중히 만든 AppConfig 위에 사뿐히 적어서 Spring에게 “야! 이게 우리 프로젝트 설정파일이다~ 알아놔라”라고 할 수 있습니다. 그리고 각각의 함수들 위에 @Bean이라고 적어줍니다. @Bean이 무엇인지는 뒤에 설명드리도록 할게요!
Spring 기반으로 변경된 AppConfig
여기서 살펴볼 점! import 목록 제일 아래 두개를 보시면 드디어 org.springframework.가 등장했습니다! 바로 드디어 스프링 사용을 시작했다는 의미예요~ @Configuration, @Bean 둘 다 springframework의 기능이라는 것을 확인하실 수 있습니다!
좋아요 어노테이션을 달아줬어요. 이제 이걸 어떻게 쓰면 될까요?
new AppConfig()를 선언했던 코드들을 생각해봐야해요. 우리는 test를 할 때 썼었죠? 어서 MemberServiceTest로 가봅시다.
우리는 이제 굳이 우리가 만든 AppConfig를 선언하지 않아도 되게 되었습니다. 한번 해보죠!
Spring 기반으로 변경된 MemberServiceTest (주석부분은 지우셔도 됩니다)
아..압니다 더 복잡해보이고 길어지는데 이걸 왜 쓰고있어야하냐는 원성의 소리 잘 들립니다.
저도 딱 봤을때 이게뭐지 했어요ㅋㅋㅋㅋ AnnotationConfigApplicationContext라니ㅋㅋㅋ 무러 34자나 되는 클래스를 선언하라는게 얼척없다는거 다 알죠…
하지만 여러분들! 굳이 이렇게 만들어서 쓰게 만드는 데에는 그만한 이유가 있겠죠? 일단은 저와같이 따라서 작성해주시면 차근차근 설명드리겠습니다ㅎㅎㅎ
우선 OrderServiceTest쪽에 선언한 AppConfig도 Spring 기반으로 바꿔줘볼까요?
Spring 기반으로 변경된 OrderServiceTest
이제 그럼 위와같이 적용했을 때 Spring은 과연 무얼 하나 알아보도록 합시다.
스프링 컨테이너와 스프링 빈
스프링 컨테이너
우리가 이름이 기니까 간단하게 ac라는 이름으로 만들었던 ApplicationContext 기억하시나요?이 친구는 스프링 컨테이너라고 합니다.
보시다시피 인터페이스인데요, 아래 코드를 보면 인자로 AppConfig.class가 들어가죠? 이렇게 작성하면 AppConfig에 담겨있는 Bean들을 담고있는 스프링의 하나의 공간이 됩니다. 그리고 이 공간을 스프링 컨테이너라고 부르는겁니다!
좋아요 그럼 계속 말하는 Bean이라는 애는 예상되듯이 함수 위에가 @Bean 어노테이션이 달렸던 애들을 얘기하는것이겠죠?
스프링 빈 예시로 우리가 만든 MemberService를 확인해보겠습니다. AppConfig에 있었던 memberService() 함수예요!
스프링 빈 - 생성
보시다시피 Bean은 클래스가 정의된것입니다.
우리는 memberRepository()에 정의한 방식으로 회원을 저장하는 MemberServiceImpl을 우리의 서비스로 사용하기로 했잖아요? 이걸 간단하게 앞으로 memberService라는 이름으로(Bean은 지정한 함수의 이름을 따릅니다) Spring의 컨테이너에 저장해놔! 라는 행동을 하게 됩니다.
그럼 우리의 스프링 컨테이너는 AppConfig를 확인해봤을 떄 memberService, orderService, memberRepository, discountPolicy라는 이름을 갖고있는 Bean 4개가 만들어지고 저장하게 되는거겠죠?
이런 형식으로 스프링은 빈들을 컨테이너에 이쁘게 저장해놓습니다.
스프링 빈 - 의존성
생성된 스프링 빈들은 자기들끼리 의존성을 생성하게 됩니다. 예를들어 memberService 빈은 memberRepository 빈을 사용하는것 처럼입니다!
화살표가 왜 이렇게 되는지는 아마 쉽게 이해하실 수 있을거예요!
스프링 빈 - 사용
우리의 Bean들이 이쁘게 저장되어있는 컨테이너를 사용하여 원하는 Bean만 꺼내먹어야할 수 있겠죠?
(냠냠)
스프링 빈은 스프링 컨테이너 안의 기능 중 getBean()이라는 함수로 꺼내서 쓸 수 있습니다.
인자값은 두개가 있네요? 첫번째는 String타입으로 원하는 스프링 빈의 이름을 넣어주면 됩니다. 두번째로는 해당 스프링 빈의 클래스 형태를 넣어주면 이제 사용이 가능합니다!
getBean()말고도 사용할 수 있는 많은 기능들이 있습니다. 다른 예로는 getBeanDefinitionNames()입니다. 함수이름처럼 해당 컨테이너 안에 있는 빈들의 이름들을 string의 리스트로 받아올 수 있는 함수죠!
이 외에도 많은 기능들이 있으니 자동완성되는 함수들 목록을 보면서 어떤 기능들이 있나 잠시 구경해보는것도 좋을 것 같아요!
이제 우리가 초반에 적용한 Spring기반으로 수정한 코드가 어떤 방식으로 동작되는지 이해가 되시죠? 그래도 아직 왜 써야하는건지 와닿지 않으시다면 이해합니다. 앞으로 이 친구들을 Bean으로 만들어 스프링이 관리하게 되었을 때 어떤 기능들을 사용할 수 있나를 알아보게 될 것입니다. 직접 이것저것 사용해보시면서 Bean으로 등록했을 때의 편리함을 느끼실 수 있었으면 좋겠습니다.
Bean 사용해보기 - 모든 Bean 조회하기
Bean을 전부 불러와서 조회해보는 테스트 코드를 작성해봅시다!
test 패키지에 beanfind라는 패키지를 만들어서 그 안에 ApplicationContextInfoTest 파일을 생성해봅시다!
그리고 바로 위에서 소개해드렸던 getBeanDefinitionNames()를 사용해서 Bean의 이름들을 전부 불러올 겁니다. 그리고 불러온 Bean이름들(String 배열이겠죠?)를 하나씩 반복문으로 가져와서 getBean()을 사용해 불러오면 될 것 같아요!
한번 이렇게 짜봅시다!
모든 Bean을 출력하는 테스트
@DisplayName()
우리가 이전에 테스트 함수를 만들 때 테스트 성공/실패 목록에서 확인하기 좋게 한국어로 함수명을 선언했었죠? 그래도 사실 함수명은 영어가 안정적이기 때문에 함수명을 영어로 쓰는 대신 테스트 목록에 내가 원하는 대로 이 테스트 함수를 표시할 수 있도록 지정해주는 어노테이션이 바로 @DisplayName입니다!
실행결과
믹숙한 것도 있고 아닌 것도 있네요!
밑에 보면 저희가 설정파일에 넣은 Bean들이 전부 잘 나오네요! 하지만 밑의 Bean들은 우리가 만든것들이라 알겠는데 위에는 뭔지 모르겠네요?
스프링이 자기들꺼 기능들을 작동하기 위해 자체적으로 만들어놓은 Bean들이랍니다. 사실 그렇다면 저희가 봐봤자 쓸데없겠죠? 저희는 저희가 만든 Bean들만 보고싶다구요!
그런 당신을 위해 준비했습니다. 바로 빈의 정의 BeanDefinition입니다!
모든 빈들은 역할을 갖고있습니다. 역할 영어로 Role이라고 하죠? 스프링의 Bean들의 Role은 크게 두분류로 나뉘어집니다.
- ROLE_APPLICATION: 직접 등록한 애플리케이션 빈
- ROLE_INFRASTRUCTURE: 스프링이 내부에서 사용하는 빈
이 Role을 확인해서 필터링하면 저희가 원하는 Bean들만 볼 수 있을 것 같습니다.
각각의 Bean들은 그 Bean의 정의들이 있습니다. 그 정의를 BeanDefinition이라는 타입으로 확인할 수 있는데요! BeanDefinition의 getRole을 통해 해당 Bean의 역할을 확인할 수 있습니다.
그럼 저희가 만든 Bean 즉 역할이 ROLE_APPLICATION인 Bean들만 조회할 수 있는 테스트코드 예시를 보여드리겠습니다.
ROLE_APPLICATION Beans만 출력하는 테스트
실행결과
이렇게 BeanDefinition을 이용해서 우리가 만든 Bean들만 조회해보는 테스트를 만들어 보았습니다.
마치며
오늘은 배운게 좀 많아요! 그래서 내가 아래의 개념들에 대해 자세히 알고 있나 한번 쭉 확인해주세요~
- @Configuration은 어디에 쓰는거고 어떤 역할을 해주는지 알고 계시나요?
- @Bean은 어디에 쓰는거고 어떤 역할을 해주는지 알고 계시나요?
- Spring의 Bean은 뭘 뜻하는 건지 알고 계시나요?
- ApplicationContext 객체를 생성하는 방법과 이 객체로 사용할 수 있는 getBeans()를 사용하는 방법을 아시나요?
- BeanDefinition 객체를 생성하는 방법과 이 객체로 사용할 수 있는 getRole()을 사용하는 방법을 아시나요?
- Bean의 역할에 대해서 크게 나뉘어지는 두 종류를 알고 계시나요?
여러번 글을 이해될 때 까지 보시다가 이 질문들에 대답하실 수 있으시다면 전부 이해하신 것이라 생각됩니다.
오늘도 복잡한 내용 들어주셔서 감사합니다!
오늘 작업한 코드의 변경 사항은 아래 커밋에서 확인하실 수 있습니다.
https://github.com/KIMB0B/blog_spring/commit/dab30bab427cb7e6cfe0e1a92c136c89c7ab0cb5