public class SingletonTest {
@Test
@DisplayName("스프링 없는 순수한 DI 컨테이너")
void pureContainer(){
AppConfig appConfig = new AppConfig();
// 1. 조회 : 호출할 때마다 객체를 생성
MemberService memberService1 = appConfig.memberService();
// 2. 조회 : 호출할 때마다 객체를 생성
MemberService memberService2 = appConfig.memberService();
// 3. 참조값이 다른 것을 확인
System.out.println("memberService1 = " + memberService1);
System.out.println("memberService2 = " + memberService2);
// memberService1과 memberService2가 다른지 자동화로 만들어보자
assertThat(memberService1).isNotSameAs(memberService2);
}
}
결과를 보면 memberService1과 memberService2는 서로 다른 객체이다. 즉, 다른 객체가 생성되어 JVM에 각각 올라가게 된다.
public class SingletonService {
// 자바의 static 영역 공부해보세요!
private static final SingletonService instance = new SingletonService();
public static SingletonService getInstance() {
return instance;
}
// 생성자를 private으로 설정해서 밖에서 못 만들게 설정
private SingletonService() {
}
public void logic() {
System.out.println("싱글톤 객체 로직 호출");
}
}
static
영역에 객체 instance
를 미리 하나 생성해서 올려둔다.getInstance()
메서드를 통해서만 조회할 수 있다.new
키워드로 객체 인스턴스가 생성되는 것을 막는다. @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);
// same (==)
// equal (Java의 eqauls 메서드)
}
싱글톤 패턴을 적용하면 고객의 요청이 올 때마다 객체를 생성하는 것이 아니라, 이미 만들어진 객체를 공유해서 효율적으로 사용할 수 있다.
하지만 싱글톤 패턴은 다음과 같은 수 많은 문제점을 가지고 있다.
구체클래스.getInstance()
private
생성자로 자식 클래스를 만들기 어렵다.💡 결론적으로 유연성이 떨어진다.
💡 안티패턴으로 불리기도 한다.
위 싱글톤 패턴의 문제점을 제거하고, 객체를 싱글톤으로 관리해주는 싱글톤 컨테이너에 대해 알아보자!