일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 공채
- OS
- 개발
- Effective Java
- 프로그래밍
- 알고리즘
- 디지털
- 신입사원
- 뮤텍스
- IT
- 깃허브
- Public
- 자바
- 세마포어
- 컴퓨터공학
- 신입
- 운영체제
- 우리카드
- 메모리
- java
- CS
- 스프링
- 정보처리기사
- package-private
- 이펙티브 자바
- 컴퓨터과학
- 깃
- spring
- github
- 스터디
Archives
- Today
- Total
주니어 개발자 성장기
(22.11.20) 10. 싱글톤 컨테이너(3) - @Configuration과 싱글톤 본문
@Configuration과 싱글톤
AppConfig.class
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(),discountPolicy());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
...
}
- memberService, orderService 빈을 만드는 코드를 보면 둘 다 memberRepository()를 호출한다.
- 그러면 new MemoryMemberRepository() 가 2번 호출되는데, 싱글톤이 깨지지 않을까?
- 스프링 컨테이너는 어떻게 이 문제를 해결할까?
MemberServiceImpl과 OrderServiceImpl
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
//테스트 용도
public MemberRepository getMemberRepository() {
return memberRepository;
}
}
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
//테스트 용도
public MemberRepository getMemberRepository() {
return memberRepository;
}
}
- 테스트 용도의 getMemberRepository 메서드를 추가했다.
public class ConfigurationSingletonTest {
@Test
void configurationTest() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
MemberServiceImpl memberService = ac.getBean("memberService",
MemberServiceImpl.class);
MemberServiceImpl memberService = ac.getBean("memberService",
MemberServiceImpl.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);
}
}
- 확인해보면 memberRepository 인스턴스는 모두 같은 인스턴스가 공유되어 사용된다.
- AppConfig의 로그를 직접 출력해보면 AppConfig의 각 메서드는 1번씩만 호출된다.
- 스프링 컨테이너가 알아서 싱글톤으로 관리해 주는 것!
- 자바 코드로는 이해할 수 없는 결과다!
@Configuration과 바이트코드 조작의 마법
스프링 컨테이너는 싱글톤 레지스트리다. 따라서 스프링 빈이 싱글톤이 되도록 보장해주어야 한다. 그런데 스프링이 자바 코드까지 어떻게 하기는 어렵다. 위 자바 코드를 보면 분명 3번 호출되어야 하는 것이 맞다.
그래서 스프링은 클래스의 바이트코드를 조작하는 라이브러리를 사용한다.
모든 비밀은 @Configuration을 적용한 AppConfig에 있다.
AppConfig 자체 출력 Test
@Test
void configurationDeep() {
ApplicationContext ac = new
AnnotationConfigApplicationContext(AppConfig.class);
//AppConfig도 스프링 빈으로 등록된다.
AppConfig bean = ac.getBean(AppConfig.class);
System.out.println("bean = " + bean.getClass());
//출력: bean = class hello.core.AppConfig$$EnhancerBySpringCGLIB$$bd479d70
}
순수한 클래스라면
'class hello.core.AppConfig' 와 같이 출력되어야 하지만,
예상과는 다르게 클래스 명에 xxxCGLIB가 붙으면서 상당히 복잡해진 것을 볼 수 있다. 이것은 프로그래머가 만든 클래스가 아니라 스프링이 CGLIB라는 바이트코드 조작 라이브러리를 사용해서 AppConfig 클래스를 상속받은 임의의 다른 클래스를 만들고, 그 다른 클래스를 스프링 빈으로 등록한 것이다!
- 그 임의의 다른 클래스가 바로 싱글톤이 보장되도록 해준다.
- @Bean이 붙은 메서드마다 이미 스프링 빈이 존재하면 존재하는 빈을 반환하고, 스프링 빈이 없으면 생성해서 스프링 빈으로 등록하고 반환하는 코드가 동적으로 만들어진다.
참고 AppConfig@CGLIB는 AppConfig의 자식 타입이므로, AppConfig 타입으로 조회 할 수 있다.
@Configuration 없이 @Bean으로만 메서드를 등록하면?
- 순수한 AppConfig가 스프링 빈에 등록된다. 하지만, 싱글톤을 보장해 주지 않고 @Bean으로 등록된 메서드와 그 내부의 메서드가 다시 실행된다.
- 즉, 서로 다른 인스턴스가 생성된다.
- 게다가, @Bean으로 직접 등록되지 않은 인스턴스들은 스프링이 관리하지 않는다.
정리
- Bean만 사용해도 스프링 빈으로 등록되지만, 싱글톤을 보장하지 않는다.
- memberRepository()처럼 의존관계 주입이 필요해서 메서드를 직접 호출할 때 싱글톤을 보장하지 않는다.
- 크게 고민할 것 없이, 스프링 설정 정보는 항상 @Configuration을 사용하자!
'Spring > 핵심' 카테고리의 다른 글
(22.11.20) 12. 컴포넌트 스캔(2) (0) | 2022.11.20 |
---|---|
(22.11.20) 11. 컴포넌트 스캔(1) (0) | 2022.11.20 |
(22.11.20) 9. 싱글톤 컨테이너(2) - 싱글톤 패턴의 주의점 (0) | 2022.11.20 |
(22.11.19) 8. 싱글톤 컨테이너(1) (0) | 2022.11.19 |
(22.11.18) 7. 스프링 컨테이너(4) - BeanDefinition (0) | 2022.11.18 |