싱글톤 컨테이너

mark1106·2024년 3월 16일
0

스프링

목록 보기
2/5
post-thumbnail

싱글톤 패턴이란?

클래스의 인스턴스가 1개만 생성되는 것을 보장하는 디자인 패턴

싱글톤 패턴 사용 이유

요청 시마다 객체를 새로 할당해야 함 -> 메모리 낭비 심하다


싱글톤 설계 예시

public class SingletonService {
    
    private static final SingletonService instance = new SingletonService();
    
    public static SingletonService getInstance(){
        return instance;
    }
    
    private SingletonService(){
    }
    
    public void logic(){
        System.out.println("싱글톤 객체 호출");
    }
}
  • static 영역에 객체 하나를 생성해둔다.
  • 생성자를 private 선언함으로써 외부에서 생성이 안되게 함
  • 사용할 때는 getInstance() 메서드를 호출하여 미리 만들어둔 객체 사용

순수 자바로 구현한 싱글톤 패턴의 문제점

  • 싱글톤 패턴 구현 코드 많음
  • 클라이언트가 구체 클래스에 의존 - DIP 위반 ex) MemberServiceImpl.getInstance() 라는 구체적 메서드를 알아야 함
  • 구체 클래스 의존하므로 OCP 위반
  • 유연성 떨어짐

싱글톤 컨테이너

스프링 컨테이너는 자동으로 싱글톤 컨테이너로 관리해 위와 같은 문제점을 해결해준다.

싱글톤 방식의 주의점

하지만 객체(인스턴스)를 공유하기 때문에 싱글톤 객체는 상태를 유지하게 설계하면 안된다!

→ ex) A가 10000원 넣고, B가 20000원 넣었을 때 A가 20000원을 사용하게 됨

따라서 무상태(stateless)로 설계해야 한다.

  • 특정 클라이언트에 의존적인 필드(위 예시와 같은 price)가 있으면 안됨
  • 특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안됨
  • 가급적 읽기만 가능해야 함
  • 필드 대신에 자바에서 공유되지 않는 지역변수, 파라미터, ThreadLocal 사용

스프링의 싱글톤 유지 방법

@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() {
        System.out.println("memberRepository!!");
        return new MemoryMemberRepository();
    }

    @Bean
    public DiscountPolicy discountPolicy() {
        return new FixDiscountPolicy();
    }
}

다음과 같은 코드가 있을 때 스프링은 @Bean이 붙은 메서드를 스프링 빈으로 등록한다.

이 때 memberRepository는 memberService에서 한 번, orderService에서 두 번, memberRepository에서 세 번 호출된다.

하지만 실제로 실행해 보면 memberRepository!!는 한 번 출력되는데 이는 스프링 컨테이너가 싱글톤으로 관리되고 있음을 의미한다.

그리고 그 역할은 @Configuration이 수행해준다.


AppConfig라는 클래스를 스프링 컨테이너에 등록할 때 AppConfig를 상속받은 다른 클래스를 만들고 그 클래스를 스프링 빈에 등록한다.

  1. AppConfig를 찾을 때 스프링 컨테이너에 AppConfig@CGLIB이 있다면 스프링 컨테이너에서 반환
  2. 없다면 스프링 컨테이너에 등록하고 반환

-> 만약 @Configuration을 제외하고 위 코드를 실행 시키면 memberRepository!!가 3번 실행됨

@Configuration 정리

@Configuration을 붙이면 해당 클래스를 상속받은 임의의 다른 클래스를 만들고 스프링 빈으로 등록한다. 따라서 이미 스프링 빈에 등록된 객체를 호출하면 기존에 등록된 빈 instance를 반환한다.

📚 참고
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard

profile
뒤돌아보면 남는 것은 사진, 그리고 기록 뿐

0개의 댓글