[Spring] 05-3. @Configuration

지찬우·2023년 1월 9일
0

Spring

목록 보기
18/27
post-thumbnail

이 시리즈는 인프런 강의(김영한 님의 ‘스프링 핵심 원리 - 기본편’)로 공부하며 혼자 기록하고, 사람들과도 공유할 수 있도록 작성하는 글이다. 최대한 추가적인 정보는 공식 홈페이지, 문서를 보며 얻을 예정이다.
(개인적인 생각과 이해가 들어가 있기 때문에 저의 ‘무식함’이 있을 수 있습니다😜 혹시라도 이 글을 보게 되시는 분이 계시다면 잘못된 부분 댓글로 많이 알려주시면 너무 감사하겠습니다!!)

GitHub Repository : https://github.com/jcw1031/spring-core-study


@Configuration

@Configuration 어노테이션의 역할에 대해 알아보자.

@Configuration과 싱글톤

AppConfig 클래스의 코드를 보면 memberService()가 호출되면 memberRepository()도 호출되어 new MemoryMemberRepository()가 호출된다. 또 orderService()가 호출되면 memberRepository()도 호출되어 한 번 더 new MemoryMemberRepository()가 호출된다.

코드로만 보면 MemoryMemberRepository가 두 개가 생성되어 싱글톤을 보장하지 못할 것처럼 보인다. 테스트를 통해 싱글톤 빈인지 확인해 보자.

테스트를 위해 MemberServiceImplOrderServiceImpl 두 개 모두 주입된 MemberRepository를 반환하는 메서드를 추가한다.


test 패키지의 singleton 패키지 내에 ConfigurationSingletonTest 테스트 클래스를 만든다. 스프링 컨테이너를 생성하고, 테스트 코드에서 MemberServiceImpl 빈과 OrderServiceImpl 빈을 조회한다.

빈을 조회할 때는 구체가 아닌 역할로 조회하는 게 좋지만, 역할이 아닌 구체 클래스로 조회한 이유는 위에서 생성한 getMemberRepository() 메서드를 사용하기 위함이다.


memberServiceorderService 각각의 MemberRepository를 조회하고, 이 둘이 같은지 확인해 보자. 테스트를 돌려보면 성공한다. 싱글톤이 보장된다는 것이다.


그럼 MemberServiceImplOrderServiceImpl에 주입된 MemberRepository가 아닌 빈으로 등록된 MemberRepository도 조회하여 비교해 보자. 테스트를 실행해 보면 3개의 MemberRepository 모두 동일한 빈임을 알 수 있다.


분명 new MemoryMemberRepository()가 여러 번 호출되어 여러 개가 생성되었을 것 같지만 모두 똑같은 빈이라는 것을 확인했다. new MemoryMemberRepository()가 여러 번 호출되는 것이 아닌지 확인해 보자.

간단하게 AppConfig에 로그를 추가해서 확인해 보자.

soutm을 입력하고 Tab을 누르면 자동으로 클래스와 메서드 이름을 출력하는 문장이 완성된다. 앞에 call만 추가해 주자.


만약 여러 번 호출된다면 로그는 아래처럼 출력될 것이다.(순서는 보장되지 않는다.)

왜 3번인지 헷갈릴 수 있다. memberRepository()에도 @Bean이 사용되었기 때문에 빈으로 등록되는 과정이 있기 때문에 세 번 호출된다고 가정할 수 있다.

/*
..memberService -> ..memberRepository -> ..memberRepository -> ..orderService -> memberRepository
*/

아까 만든 테스트 코드를 그대로 실행해 보면, memberRepository 로그가 세 번 찍힐 것이라 예상한 것과 달리 한 번만 출력된다.

어떻게 스프링 컨테이너는 싱글톤 빈을 보장할까?

바이트 코드 조작

비밀은 @Configuration AppConfig에 있다.

AppConfig를 출력해 보자. AppConfig도 빈으로 등록되니 getBean()을 통해 빈을 조회하고 출력한다.


출력 결과를 보면 그냥 AppConfig가 아닌 뒤에 무언가 붙어있는 것을 확인할 수 있다. 순수한 클래스라면 bean = class Group이름.core.AppConfig라고 출력되었을 것이다.


뒤에 ~CGLIB이 붙어있다. 이것은 우리가 만든 클래스가 아닌, 스프링이 CGLIB이라는 바이트 코드 조작 라이브러리를 사용해 AppConfig 클래스를 상속받은 임의의 다른 클래스를 생성해 이를 스프링 빈으로 등록한 것이다.

우리가 코드의 깊숙한 내부를 알 수는 없지만, 만약 MemoryMemberRepository가 빈으로 등록되어 있는지 확인한 후에 등록되어 있지 않으면 새로 빈으로 등록하고, 등록되어 있다면 새로 빈을 등록하지 않고 기존 빈을 주입해 주는 형식으로 내부 코드를 조작했을 것이라고 예상해 볼 수 있겠다.


@Configuration을 사용하지 않는다면❓

@Configuration 어노테이션을 사용하지 않으면 싱글톤 패턴이 깨지는지 확인해 보자.

AppConfig@Configuration을 주석 처리한다.


동일하게 테스트를 실행해 보면, 순수한 AppConfig 클래스가 스프링 빈에 등록된다.


configurationTest를 실행해 보면, memberRepository가 세 번 호출되고 객체를 확인해 보면 모두 다른 객체임을 알 수 있다.

MemberServiceImplOrderServiceImplprivate final MemberRepository memberRepository;에 주입된 것은 스프링 빈이 아니다. private final MemberRepository memberRepository = new MemoryMemberRepository;와 동일하다. 스프링 컨테이너가 관리하지 않는 객체인 것이다.


스프링 설정 정보는 항상 @Configuration을 사용하도록 한다. 스프링 컨테이너가 싱글톤 빈을 보장할 수 있었던 비밀이 @Configuration 어노테이션에 있다는 것을 알아보았다. 다음 시간에는 컴포넌트 스캔에 대해 공부한다.

profile
좋은 개발자가 되자.

0개의 댓글