프로그래밍/Spring
[ Spring ] DI 컨테이너와 싱글톤
Yanoo
2022. 2. 4. 15:00
728x90
반응형
<인프런의 김영한님의 강의를 보고 정리한 내용입니다>
스프링 컨테이너를 사용하지 않으면 싱글톤이 적용되지 않는다. 간단히 테스트를 해보면,
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public MemoryMemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
@Bean
public DiscountPolicy discountPolicy() {
// return new FixDiscountPolicy();
return new RateDiscountPolicy();
}
}
@Test
@DisplayName("스프링 없는 순수한 DI 컨테이너")
void pureContainer() {
AppConfig appConfig = new AppConfig();
//1. 조회: 호출할 떄 마다 객체를 생성
MemberService memberService1 = appConfig.memberService();
//2. 조회: 호출할 때 마다 객체를 생성
MemberService memberService2 = appConfig.memberService();
//참조값이 다른 것을 확인
System.out.println("memberService1 = " + memberService1);
System.out.println("memberService2 = " + memberService2);
// memberService1 != memberService2
assertThat(memberService1).isNotSameAs(memberService2);
}
테스트 코드를 작성하고 확인해보면,
다른 인스턴스가 생성된 것을 확인할 수 있다. 이렇게 매번 다른 인스턴스가 생성되면 효율성이 떨어질 것이다. 이런 단점을 해결하기 위해서 싱글톤으로 코드를 작성해야 한다.
public class SingletonService {
private static final SingletonService instance = new SingletonService();
public static SingletonService getInstance() {
return instance;
}
// new 키워드로 외부에서 인스턴스가 생성되는 것을 막음
private SingletonService() {
}
public void logic() {
System.out.println("싱글톤 객체 로직 호출출");
}
}
이런 식으로 적용해서
@Test
@DisplayName("싱글톤 패턴을 적용한 객체 사용")
void singletonServiceTest() {
SingletonService singletonService1 = SingletonService.getInstance();
SingletonService singletonService2 = SingletonService.getInstance();
System.out.println("singletonService1 = " + singletonService1);
System.out.println("singletonService2 = " + singletonService2);
assertThat(singletonService1).isSameAs(singletonService2);
}
테스트를 하면
같은 인스턴스임을 확인할 수 있다. 그런데 이런 싱글톤의 단점은 뭘까?
🎈싱글톤의 문제점
- 싱글톤 패턴을 구현하는 코드 자체가 많이 들어간다.
- 의존관계상 클라이언트가 구체 클래스에 의존한다. -> DIP 위반
- 클라이언트가 구체 클래스에 의존해서 OCP 원칙을 위반할 가능성이 높다.
- 테스트하기 어렵다.
- 내부 속성을 변경하거나 초기화 하기 어렵다.
- private 생성자로 자식 클래스를 만들기 어렵다.
- 결론적으로 유연성이 떨어진다.
- 안티패턴으로 불리기도 한다.
이 문제들을 해결하기 위해 사용하는 것이, 스프링 컨테이너이다. 스프링 컨테이너를 사용하면 이 문제점을 해결해 주는데,
🎁 스프링 컨테이너는 싱글톤 패턴을 적용하지 않아도, 객체 인스턴스를 싱글톤으로 관리한다.
🎁 스프링 컨테이너는 싱글톤 컨테이너 역할을 한다. 이렇게 싱글톤 객체를 생성하고 관리하는 기능을 싱글톤 레지스트리라 한다.
🎁 스프링 컨테이너의 이런 기능으로 싱글톤의 단점을 해결하고 객체를 싱글톤으로 유지할 수 있다.
- 싱글톤 패턴을 위한 추가적인 코드 작성 필요 X
- DIP, OCP, 테스트, private 생성자로 부터 자유롭게 싱글톤을 사용할 수 있음.
이제 싱글톤으로 적용됐는지 확인해보면,
@Test
@DisplayName("스프링 컨테이너와 싱글톤")
void springContainer() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
//1. 조회: 호출할 떄 마다 객체를 생성
MemberService memberService1 = ac.getBean("memberService", MemberService.class);
MemberService memberService2 = ac.getBean("memberService", MemberService.class);
//참조값이 다른 것을 확인
System.out.println("memberService1 = " + memberService1);
System.out.println("memberService2 = " + memberService2);
// memberService1 != memberService2
assertThat(memberService1).isSameAs(memberService2);
}
잘 적용된 것을 알 수 있다.
참고로 기본 빈 등록방식은 싱글톤이지만, 다른 방식도 지원한다.
728x90
반응형