AnnotationConfigApplicationContext( TestConfig.class )
위의 코드에서 스프링컨테이너에 직접 빈을 등록해주었기 때문에 가능하다.
이와 같은 경우에도 싱글톤으로 관리가 된다.
@Test
void configurationTest() {
ApplicationContext ac = new
AnnotationConfigApplicationContext(AppConfig.class);
MemberServiceImpl memberService = ac.getBean("memberService",
MemberServiceImpl.class);
OrderServiceImpl orderService = ac.getBean("orderService",
OrderServiceImpl.class);
MemberRepository memberRepository = ac.getBean("memberRepository",
MemberRepository.class);
//모두 같은 인스턴스를 참고하고 있다.
System.out.println("memberService -> memberRepository = " +
memberService.getMemberRepository());
System.out.println("orderService -> memberRepository = " +
orderService.getMemberRepository());
System.out.println("memberRepository = " + memberRepository);
//모두 같은 인스턴스를 참고하고 있다.
assertThat(memberService.getMemberRepository()).isSameAs(memberRepository);
assertThat(orderService.getMemberRepository()).isSameAs(memberRepository);
}
테스트 코드 작성 시 orderService에서도 memberRepository를 사용하지만 인스턴스 생성은 1번씩만 된 것을 볼 수 있다. => CGLIB의 사용
참고 링크 - https://yhmane.tistory.com/129
[정리]
Component와 Bean
https://youngjinmo.github.io/2021/06/bean-component/
@Component
@Configuration + @Bean
그러나 개발자가 직접 작성한 클래스를 @Configuration+@Bean으로 등록할 수도 있다.
TestClass에서 AppConfig를 직접 등록하는 경우
@Bean
public MemberRepository memberRepository() {
System.out.println("AppConfig.memberRepository");
return new MemoryMemberRepository();
}
스프링이 빈을 등록할 때 memberRepository()를 호출한다.
@Bean
public MemberService memberService() {
System.out.println("AppConfig.memberService");
return new MemberServiceImpl(memberRepository());
}
그러나 memberService에서 memberRepository()를 호출하게 되면 내부에서 new ~로 새로운 객체가 생성된다.
이 문제를 해결해주는 것이 @Configuration이다.
bean = class hello.core.AppConfig$$EnhancerBySpringCGLIB$$bd479d70
AppConfig 빈을 조회해보면 뒤에 CGLIB가 붙은 것을 볼 수 있다.
=> 내가 만든 클래스가 아니라 스프링이 CGLIB라는 바이트코드 조작 라이브러리를 사용해서 AppConfig를 상속받은 임의의 클래스를 만들고, 그 다른 클래스를 스프링 빈으로 등록한 것이다.
**이를 통해서 단순 자바 코드로 호출되는 memberRepository()를 빈으로 대체해서 전달해줄 수 있게 된다. **