싱글톤(singleton) 패턴

2022. 9. 24. 15:17자바 & Spring

싱글톤 패턴이란?

  • 클래스의 인스턴스가 한개만 생성되는 것을 보장하는 디자인 패턴.
  • 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고, 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다.

싱글톤 패턴은 같은 클래스의 인스턴스를 한개만 생성되게 하는 패턴이다.

말 그대로 같은 타입의 생성자가 여러차례 호출돼도 원래 생성되어있던 동일한 객체만이 리턴된다.

프로그램 내에 하나의 객체만 존재해야 할 때나, 프로그램 내에 해당 객체를 공유하며 사용해야 할 때 필요하다.

 

 

스프링 컨테이너

스프링 컨테이너(DI, IoC 컨테이너)는 객체 인스턴스를 싱글톤으로 관리해준다.

컨테이너는 @Bean이 붙은 어노테이션을 스프링 빈으로 관리한다. 이는 싱글톤으로 관리된다.

ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
        
MemberService memberService1 = ac.getBean("memberService", MemberService.class);
MemberService memberService2 = ac.getBean("memberService", MemberService.class);

memberService1, memberService2 는 같은 객체이다.

스프링 컨테이너 덕분에 요청이 올 때마다 이미 만들어진 객체를 공유해 효율적으로 재사용할 수 있다.

 

이처럼 싱글톤 인스턴스는 여러 클라이언트 코드에서 공유되기 때문에, 무상태(stateless)로 설계해야 한다.

 

 

싱글톤 설계방식 : Stateless (무상태)

  • 특정 클라이언트에 의존적인 필드가 없도록 설계
  • 특정 클라이언트가 값을 변경할 수 없도록 설계
  • Read-Only 인 것이 좋다.

싱글톤 객체 필드에 공유되는 변수를 설정하면 큰 문제가 발생할 수 있다.

 

 

자바 싱글톤 예제

public class Singleton {
    private static Singleton singleton = new Singleton();
    
    private Singleton(){}
    
    private Singleton getInstance(){
    	return s;
    }
}

생성자를 private 으로 막아 Singleton 외부에서 new 로 Singleton 인스턴스를 생성하는 것을 막는다.

static 필드를 통해 모든 Singleton 객체가 공유하는 필드를 만들 수 있으며 이 필드는 getInstance() 를 통해서만 가져올 수 있디.

늘 같은 하나의 인스턴스를 반환하기 때문에 싱글톤 패턴을 만족하는 클래스이다.

 

 

스프링은 설정파일을 참고해 스프링컨테이너로 스프링 빈을 관리한다. 스프링은 어떻게 스프링 빈을 싱글톤으로 관리할까?

 

@Configuration 과 바이트코드 조작

스프링 컨테이너는 싱글톤 레지스트리이다. 따라서 스프링 빈이 싱글톤이 되도록 보장해준다.

코드에서 같은 클래스의 생성자를 3번 호출했다고 하자. 그럼 생성자를 3번 호출했으니, 해당클래스의 생성자가 3번 호출이 되면 싱글톤이 안 지켜지는 게 아닐까? 라는 의문이 든다.

 

스프링은 이 문제를 클래스의 바이트코드를 조작함으로써 해결한다.

ApplicationContext ac = new
  AnnotationConfigApplicationContext(AppConfig.class);

 

위와 같이 AnnotationConfigApplicationConext() 인자로 넘긴 값은 스프링 빈으로 등록된다.

이 때 CGLIB 라는 바이트코드 조작 라이브러리를 사용해 AppConfig 클래스를 상속받는, 임의의 다른 클래스를 스프링 빈으로 등록한다.

 

 

AppConfig 를 상속받은 클래스가 있고 이를 AppConfig@CGLIB 라고 하자. (이름은 그냥 예시임)

AppConfig@CGLIB 라는 임의의 클래스가 스프링 빈으로 등록되고, 이 임의의 클래스가 싱글톤을 보장해준다.

 

  • @Bean이 붙은 메서드마다 이미 스프링 빈이 존재하면 존재하는 빈을 반환한다.

  • 컨테이너에 없으면 새로 생성해서 컨테이너에 등록, 해당 객체 반환

 

즉 원래의 AppConfig 클래스에는 위 기능이 없지만, 빈으로 등록된 AppConfig@CGBLIB~~ 에 추가된 기능이라고 볼 수 있겠다.

@Bean 이 붙은 메서드마다 이미 존재하는 빈이라면 해당 빈을 반환하고, 없으면 새로 생성해 반환하여 싱글톤 패턴을 지키게 되는 것!

 

 

위에서는 @Configuration 이 붙은 AppConfig 설정 정보 클래스를 통해 스프링이 컨테이너를 생성, 빈을 싱글톤으로 관리해준다는 것을 알았다. 그렇다면 AppConfig 없이 @Bean 으로만 싱글톤 관리가 가능할까?

 

결론부터 말하자면 불가능하다. 

@Bean으로 스프링 빈을 등록할 순 있지만, 싱글톤을 보장하지 않는다.

'자바 & Spring' 카테고리의 다른 글

빈 생명주기 콜백  (0) 2022.10.26
컴포넌트 스캔, 의존관계 자동 주입  (2) 2022.09.25
Spring 특징과 장점  (0) 2022.09.17
JUnit 단위 테스트  (0) 2022.09.07
타임리프(thymeleaf)  (0) 2022.05.04