싱글톤 컨테이너

야부엉·2024년 8월 2일
0

SPRING

목록 보기
45/45
post-thumbnail

싱글톤 컨테이너

이 내용은 김영한 교수님(?)의 스프링 핵심 원리 - 기본편 강의를 들으며 정리한 내용입니다.

1. 싱글톤이 필요한 이유

스프링 애플리케이션을 웹 애플리케이션으로 사용한다고 가정해보자.(신기하게도 웹이 아닌 데몬 형태로도 스프링 애플리케이션을 쓸 수 있다)

여러 명의 클라이언트가 요청을 보내는 경우, 순수 자바인 경우 요청이 올 때마다, 객체를 생성하게 된다.
즉, 객체 생성에 의한 메모리 낭비가 심하게 된다.
그렇다면 해결법은 뭘까?
-> 싱글톤 패턴을 도입해서 해당 객체를 공유하면 된다.

2. 싱글톤 패턴

싱글톤 패턴은 인스턴스가 딱 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("싱글톤 객체 로직 호출");
    }

}
  • 위의 코드가 간단하게 싱글톤 패턴을 적용한 코드이고, private static final을 통해 공통적으로 하나의 인스턴스를 사용하게 만들었습니다.
  • 여기서 중요한 것은 private 생성자를 통해 new 객체 생성을 막은 것입니다.
  • 여기서 주의할 점은 하나의 객체 인스턴스를 공유하기 때문에 무상태로 설계해야한다.즉, 값을 변경할 수 있는 필드가 있으면 안된다.

3. 싱글톤 문제점

  • 싱글톤 패턴을 구현하는 코드 자체가 많다.
  • 클라이언트가 구체 클래스에 의존 -> DIP, OCP 위반
  • 유연성이 떨어진다 등등 많은 문제점이 있다. 그렇다면 이러한 문제점을 스프링에서 어떻게 해결했는지 알아보자

4. 싱글톤 컨테이너


위의 그림은 스프링 컨테이너의 생성 과정을 나타낸 것이다.
스프링 컨테이너는 키 값이 빈 이름이고 밸류가 빈 객체인 하나의 맵의 형태의 빈 저장소를 가지고 있다. 이러한 형태로 싱글톤 패턴을 적용하지 않아도 알아서 객체 인스턴스를 싱글톤으로 관리한다. -> 싱글톤 레지스트리라고 한다.
즉, 위의 형태이기 때문에 싱글톤의 문제점을 해결할 수 있었다.

5. 바이트 코드 조작

@Configuration
public class AppConfig {
	@Bean
    public MemberService memberService() {
        System.out.println("call AppConfig.memberService");
        return new MemberServiceImpl(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository() {
        System.out.println("call AppConfig.memberRepository");
        return new MemoryMemberRepository();
    }

    @Bean
    public OrderService orderService() {
        System.out.println("call AppConfig.orderService");
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }

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

}

위의 코드와 같이 AppConfig.class 작성하고 나면, 의문이 들 것이다. memeberService를 호출하면, memberRepositry가 불러지면서 MemoryMemberRepository가 새로 만들어지고, memberRepository를 호출하면 또 새로운 MemoryMemberRepository 객체가 만들어 질 것이고, 또 orderService를 호출하면 새로운 객체가 만들어 질 것이다. 즉, 아래와 같이 출력이 될 것이라고 생각할 것이다. (순서는 다를 수 있다)
1. call AppConfig.memberService
2. call AppConfig.memberRepository
3. call AppConfig.memberRepository
4. call AppConfig.orderService
5. call AppConfig.memberRepository

그렇다면 실제로는 어떻게 될까?
아래의 그림과 같이 출력이 된다.

오잉 왜 세 번만 출력이 되는거지??

그이유는 스프링은 클래스의 바이트코드를 조작하는 라이브러리를 사용하기 때문이다.

그림과 같이 AppConfig를 상속하는 AppConfig@CGLIB클래스를 생성하여 이 클래스가 스프링 빈으로 등록된다. -> 바이트 코드를 조작해서 새로운 클래스 작성

결론은 @Configuration 을 붙이면 바이트코드를 조작하는 CGLIB 기술을 사용해서 싱글톤을 보장하게 된다.

  • 만약 @Configuration 이 없으면, 스프링 빈으로 등록은 가능하지만, 싱글톤을 보장하지 않는다.

출처

스프링 핵심원리 - 기본편 (김영한 교수님)

profile
밤낮없는개발자

1개의 댓글

comment-user-thumbnail
2024년 8월 2일

싱글톤에 관해 학습하신 내용 잘 작성해주셨군요! 앞으로도 꾸준히 학습하신 내용 기록해보면서 작성해보아요~!👍

답글 달기