🧐강의🧐
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard
🫧 궁금증
· AppConfig 에서 MemoryMemberRepository 가 2 번 호출되면서 싱글톤이 깨지지는 않을까 ??
@Configuration
public class AppConfig {
// @Bean memberService -> new MemoryMemberRepository()
// @Bean orderService -> new MemoryMemberRepository()
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public MemoryMemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
...
}
TEST
☑️ MemoryMemberRepository 를 호출하는 MemberServiceImpl 과 OrderServiceImpl 의 객체 확인하기
1. MemberServiceImpl 에 테스트 코드 추가
public class MemberServiceImpl implements MemberService{
...
// 테스트 용도
public MemberRepository getMemberRepository() {
return memberRepository;
}
}
2. OrderServiceImpl 에 테스트 코드 추가
public class OrderServiceImpl implements OrderService{
...
// 테스트 용도
public MemberRepository getMemberRepository() {
return memberRepository;
}
}
3. test/java/hello.core/singleton/ConfigurationSingletonTest Class 생성
public class ConfigurationSingletonTest {
@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);
MemberRepository memberRepository1 = memberService.getMemberRepository();
MemberRepository memberRepository2 = orderService.getMemberRepository();
System.out.println("memberService -> memberRepository = " + memberRepository1);
System.out.println("orderService -> memberRepository = " + memberRepository2);
System.out.println("memberRepository = " + memberRepository);
Assertions.assertThat(memberService.getMemberRepository()).isSameAs(memberRepository);
Assertions.assertThat(orderService.getMemberRepository()).isSameAs(memberRepository);
}
}
AppConfig 에서 호출 로그 확인하기
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
// soutm
System.out.println("call AppConfig.memberService");
return new MemberServiceImpl(memberRepository());
}
@Bean
public MemoryMemberRepository memberRepository() {
System.out.println("call AppConfig.memberRepository");
return new MemoryMemberRepository();
}
@Bean
public OrderService orderService() {
System.out.println("call AppConfig.orderService");
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
...
}
☑️ 예상 call 호출 (순서 보장X)
→ call AppConfig.memberService
→ call AppConfig.memberRepository
→ call AppConfig.memberRepository
→ call AppConfig.orderService
→ call AppConfig.memberRepository
✅ 실제 call 호출
→ call AppConfig.memberService
→ call AppConfig.memberRepository
→ call AppConfig.orderService
🫧 궁금증 해결
· 스프링은 클래스의 바이트코드를 조작하는 라이브러리를 사용 → CGLIB
· 비밀은 @Configuration 을 적용한 AppConfig 에 .. !!
TEST
☑️ 내가 만든 클래스가 아닌, CGLIB 라이브러리를 이용한 임의의 다른 클래스가 스프링 빈 등록한 것 확인하기
public class ConfigurationSingletonTest {
...
@Test
void configurationDeep() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
AppConfig bean = ac.getBean(AppConfig.class);
System.out.println("bean = " + bean.getClass());
}
}
➡️ 스프링이 CGLIB(바이트코드 조작 라이브러리)를 이용해 AppConfig 를 상속받은 임의의 다른 클래스 생성 후 스프링 빈으로 등록
· 예상 코드
@Bean
public MemberRepository memberRepository() {
if (memoryMemberRepository 가 이미 스프링 컨테이너에 등록되어 있으면) {
return 스프링 컨테이너에서 찾아서 반환;
} else { // 스프링 컨테이너에 없으면
기존 로직을 호출해서 MemoryMemberRepository 를 생성하고 스프링 컨테이너에 등록
return 반환
}
}
@Configuration 삭제 시
☑️ @Configuration 을 적용하지 않고, @Bean 만 적용 → AppConfig 에서 @Configuration 삭제
// @Configuration
public class AppConfig { ... }
➡️ 각자 다른 MemoryMemberRepository 인스턴스를 가지고 있음
정리
- @Bean 만 사용해도 스프링 빈 등록 가능 (싱글톤 보장X)
- 항상 @Configuration 사용하기 !!
'Spring > 스프링 핵심 원리 - 기본편' 카테고리의 다른 글
[컴포넌트 스캔] 기본 스캔 대상 (1) | 2023.12.07 |
---|---|
[컴포넌트 스캔] @Component, @Autowired - 의존 관계 자동 주입 (0) | 2023.12.05 |
[싱글톤 컨테이너] 싱글톤 방식의 주의점 - 무상태(stateless) 설계 (0) | 2023.11.30 |
[싱글톤 컨테이너] 싱글톤 패턴의 문제를 해결하는 스프링 컨테이너 (0) | 2023.11.29 |
[스프링 컨테이너와 스프링 빈] BeanDefinition - 스프링 빈 설정 메타 정보 (0) | 2023.11.25 |