Notice
«   2025/01   »
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
01-09 18:44
Today
Total
관리 메뉴

그날그날 공부기록

싱글톤 컨테이너 본문

Spring 공부

싱글톤 컨테이너

given_dragon 2022. 7. 19. 17:27
public class SingletonTest {

    @Test
    @DisplayName("스프링 없는 순수한 DI 컨테이너")
    void pureContainer(){
        AppConfig appConfig = new AppConfig();

        //1. 조회: 호출할 때 마다 객체를 생성
        MemberService memberService = appConfig.memberService();

        //2. 조회: 호출할 때 마다 객체를 생성
        MemberService memberService2 = appConfig.memberService();

        //참조값이 다른 것을 확인
        System.out.println("memberService = " + memberService);
        System.out.println("memberService2 = " + memberService2);
        Assertions.assertThat(memberService).isNotSameAs(memberService2);
    }
}

위의 코드처럼 요청마다 새로운 인스턴스를 생성하고, 삭제하게 된다면 메모리의 낭비가 매우 심해진다.

이에 대한 해결방안은 인스턴스를 하나만 생성하는 것이다.

인스턴스를 하나만 생성하고, 공유시킨다면 메모리의 낭비를 없앨 수 있다.

이렇게 인스턴스가 1개만 생성되는 것을 보장하는 것이 바로 싱글톤 디자인 패턴이다.


싱글톤 패턴

싱글톤 패턴을 구현하는 예 중 하나를 적용해보았다.

public class SingletonService {

    //static으로 객체를 하나만 생성.
    private static final SingletonService instance = new SingletonService();

    //해당 static 메서드로만 인스턴스 조회를 허용
    public static SingletonService getInstance() {
        return instance;
    }

    //private 생성자로 외부에서 new 키워드를 이용한 객체 생성 차단.
    private SingletonService(){}

    public void logic(){
        System.out.println("싱글톤 객체 로직 호출");
    }
}

SingletonService 인스턴스를 static으로 하나만 생성한다.

생성된 인스턴스를 조회하기 위해 public으로 조회 메서드를 생성한다.

생성자를 private으로 선언해서 SingletonService 객체를 외부에서 생성할 수 없도록 한다.

→ getInstance()로 조회하면 항상 같은 인스턴스를 사용한다.

 

실제 같은 인스턴스가 조회되는지 확인하기 위해 코드를 작성하여 확인해보면

@Test
@DisplayName("싱글톤 패턴을 적용한 객체 사용")
void singletonServiceTest(){
    SingletonService service1 = SingletonService.getInstance();
    SingletonService service2 = SingletonService.getInstance();

    System.out.println("service1 = " + service1);
    System.out.println("service2 = " + service2);
        Assertions.assertThat(service1).isSameAs(service2);
        //Assertions.assertThat(service1).isEqualTo(service2);
}

다음과 같이 동일한 객체임을 확인할 수 있다.

싱글톤 패턴을 사용하면 앞서 말한 장점도 있지만 단점 또한 존재한다.

  • 싱글톤 패턴을 구현하는 코드가 항상 필요하다
  • 의존관계상 클라이언트가 구체 클래스에 의존해 DIP를 위반하게 된다.
  • DIP를 위반하기 때문에 OCP 역시 위반할 가능성이 높다.
  • 유연한 테스트를 하기 어렵다.
  • 내부 속성을 변경하거나 초기화 하기 어렵다.
  • private 생성자로 자식 클래스를 만들기 어렵다.
  • 유연성이 떨어진다.

이러한 단점 때문에 안티패턴이라고 불리기도 한다.


싱글톤 컨테이너

스프링 컨테이너는 직접 싱글톤 패턴을 적용하지 않아도 객체들을 싱글톤으로 관리하고, 위에서 말한 싱글톤 패턴의 단점을 해결해준다.

→ 사용자는 해당 패턴이나 단점에 얽매이지 않고 자유롭게 사용할 수 있다. 

 

스프링 컨테이너는 싱글톤 컨테이너의 역할을 한다. 이렇게 싱글톤 객체를 생성하고 관리하는 기능을 싱글톤 레지스트리라고 한다.

 

맨 처음 작성한 코드를 스프링 컨테이너를 사용하여 다시 작성해 보았다.

@Test
@DisplayName("스프링 컨테이너와 싱글톤")
void springContainer(){
    //AppConfig appConfig = new AppConfig();
    ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

    //1. 조회: 호출할 때 마다 객체를 생성
    MemberService memberService = ac.getBean("memberService", MemberService.class);
    //2. 조회: 호출할 때 마다 객체를 생성
    MemberService memberService2 = ac.getBean("memberService", MemberService.class);

    //참조값이 같은 것을 확인
    System.out.println("memberService = " + memberService);
    System.out.println("memberService2 = " + memberService2);
    Assertions.assertThat(memberService).isSameAs(memberService2);
}

AppConfig 설정파일에는 싱글톤 패턴과 관련된 코드가 하나도 없지만 스프링 컨테이너는 객체들을 알아서 싱글톤으로 관리해준다.

싱글톤으로 관리되는 같은 Bean을 호출하였으므로 당연히 같은 인스턴스인 것을 확인할 수 있다.

 

스프링 컨테이너는 기본적으로 빈을 싱글톤으로 관리하지만 요청할 때 마다 새로운 객체를 생성하여 반환하게 할 수도 있다고 한다.

'Spring 공부' 카테고리의 다른 글

스프링의 @Configuration과 싱글톤  (0) 2022.07.21
싱글톤 방식의 주의점  (0) 2022.07.21
BeanDefinition  (0) 2022.07.18
BeanFactory & ApplicationContext  (0) 2022.07.15
스프링 빈 조회  (0) 2022.07.11
Comments