@Configuration과 싱글톤
➡️ 의문점 : 각 Bean에서 같은 인스턴스가 생성되며(MemoryMemberRepository) 싱글톤이 깨지는 것 처럼 보임
@Bean //스프링 컨테이너에 등록
public MemberService memberService(){ //호출 시 MemoryMemberRepository()호출
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService(){ //호출 시 MemoryMemberRepository()호출
return new OrderServiceImpl(
memberRepository(),
discountPolicy()
);
}
➡️ 하지만 조회해보면 싱글톤이 유지되는 것을 알 수 있음 >> Configuration의 역할
@Bean
public MemberRepository memberRepository() {
System.out.println("call AppConfig.memberRepository"); //세 번 호출될 것 같지만 한 번만 호출됨(Configuration의 힘)
return new MemoryMemberRepository(); // 데이터 저장 수정시 해당 부분만 수정
}
package hello.core.singleton;
import hello.core.AppConfig;
import hello.core.member.MemberRepository;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.order.OrderServiceImpl;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static org.assertj.core.api.Assertions.*;
public class ConfigurationSingletonTest {
@Test
void configurationTest(){
AnnotationConfigApplicationContext 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 -> memberRepository1 = " + memberRepository1);
System.out.println("orderService -> memberRepository2 = " + memberRepository2);
System.out.println("memberRepository = " + memberRepository);
// 모두 같은 인스턴스 조회됨
assertThat(memberService.getMemberRepository()).isSameAs(memberRepository);
assertThat(orderService.getMemberRepository()).isSameAs(memberRepository);
// 모두 같은 인스턴스 참고함
}
}
@Configuration과 바이트코드 조작의 마법
➡️ 스프링이 싱글톤을 보장해야 하지만 자바 코드까지 조작하기는 어렵다.
➡️ AppConfig를 조회해보면 순수 클래스가 아닌 xxxCGLIB가 붙은 클래스로 조회됨
🔸내가 만든 클래스가 아니라, 스프링이 CGLIB라는 바이트코드 조작 라이브러리로 임의의 클래스를 생성하고 상속해서 등록 >> 싱글톤을 보장해 줌
🔸상속했기 때문에 AppConfig로 조회해도 조회가 가능(자식이기 때문에)


@Test
void configurationDeep(){
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
AppConfig bean = ac.getBean(AppConfig.class);
System.out.println("bean = " + bean.getClass());
}
➡️ AppConfig@CGLIB 예상 코드
@Bean
public MemberRepository memberRepository() {
if (memoryMemberRepository가 이미 스프링 컨테이너에 등록되어 있으면?) {
return 스프링 컨테이너에서 찾아서 반환;
} else { //스프링 컨테이너에 없으면
기존 로직을 호출해서 MemoryMemberRepository를 생성하고 스프링 컨테이너에 등록
return 반환
}
}
➡️ 만약 @Configuration이 없이 @Bean만 적용한다면?
🔸빈 등록은 가능
🔸싱글톤을 보장하지 않음 (CGLIB가 아닌 순수 클래스가 등록됨)
* 김영한님의 스프링 핵심 원리 - 기본편을 요약 및 정리한 내용입니다 *
'프로그래밍 > - Spring' 카테고리의 다른 글
| [ 의존관계 자동 주입 ] 다양한 의존관계 주입 방법 / 옵션 처리 / 생성자 주입을 선택해라! / 롬복과 최신 트렌드 (0) | 2025.03.20 |
|---|---|
| [ 컴포턴트 스캔 ] 컴포넌트 스캔과 의존관계 자동 주입 시작하기 (0) | 2025.03.18 |
| [ 싱글톤 컨테이너 ] 웹 애플리케이션과 싱글톤 ~ 싱글톤 방식의 주의점 (0) | 2025.03.13 |
| [ 스프링 컨테이너와 스프링 빈 ] BeanFactory와 ApplicationContext ~ 스프링 빈 설정 메타 정보 - BeanDefinition (1) | 2025.03.13 |
| [ 스프링 컨테이너와 스프링 빈 ] 스프링 컨테이너 생성 ~ 스프링 빈 조회 (1) | 2025.03.12 |