본문 바로가기
프로그래밍언어/Java

[Java] 스프링과 싱글톤 패턴의 관계 (Configuration)

by Yikanghee 2022. 1. 19.

스프링과 싱글톤 패턴의 관계 (Configuration)

  • 싱글톤 패턴
    • 클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴
    • private final로 인스턴스를 생성하여 외부에서 new 키워드를 사용하지 못하도록 막아야함
  • 싱글톤 패턴을 지킨 코드
    • getInstance 메서드를 통해서만 인스턴스를 생성할 수 있고
    • private 생성자를 선언하여 외부에서 new 키워드로 접근하는 것을 막음
public class SingletonService {

 //1. static 영역에 객체를 딱 1개만 생성해둔다.
 private static final SingletonService instance = new SingletonService();

 //2. public으로 열어서 객체 인스터스가 필요하면 이 static 메서드를 통해서만 조회하도록
허용한다.
 public static SingletonService getInstance() {
 return instance;
 }

 //3. 생성자를 private으로 선언해서 외부에서 new 키워드를 사용한 객체 생성을 못하게 막는다.
 private SingletonService() {
 }
  • 싱글톤의 문제점
    • 싱글턴 패턴을 구현하는 코드 자체가 많이 들어간다
    • 의존관계상 클라이언트가 구체를 클래스에 의존한다 → DIP 위반
    • 클라이언트가 구체 클래스에 의존해서 OCP 원칙을 위반할 가능성이 높다
    • 테스트하기 어렵다
    • 내부 속성을 변경하거나 초기화 하기 어렵다
    • private 생성자로 자식 클래스를 만들기 어렵다]
    • 결론적으로 유연성이 많이 떨어진다
    • 안티패턴으로 불리기도 한다
    • 이러한 싱글톤 패턴을 사용하는데 있어서 스프링 사용은 필수적이고 취약점을 보안해준다
  • 싱글톤 컨테이너
    • 스프링 컨테이너는 싱글톤 패턴의 문제점을 해결하면서, 객체 인스턴스를 싱글톤(1개만
    • 생성) 으로 관리한다
    • 스프링 컨테이너는 싱글톤 패턴을 적용하지 않아도, 객체 인스턴스를 싱글톤으로 관리한다
    • 스프링 컨테이너는 싱글톤 컨테이너 역할을 한다. 이렇게 싱글톤 객체를 생성하고 관리하는 기능을 싱글톤 레지스트리라 한다
    • 스프링 컨테이너의 이런 기능 덕분에 싱글톤 패턴의 모든 단점을 해결하면서 객체를 싱글톤으로 유지할 수 있다
    • 싱글톤 패턴을 위한 지저분한 코드가 들어가지 않아도 된다
    • DIP, OCP,테스트,private 생성자로 부터 자유롭게 싱글톤을 사용할 수 있다
  • 스프링 컨테이너를 사용하여 싱글톤이 지켜지는 지 확인
@TEST
@DisplayName("스프링 컨테이너와 싱글톤")
void springContainer() {
	
	ApplicatinContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
	
	//1. 조회: 호출할 때 마다 같은 객체를 반환
 MemberService memberService1 = ac.getBean("memberService",MemberService.class);

 //2. 조회: 호출할 때 마다 같은 객체를 반환
 MemberService memberService2 = ac.getBean("memberService",MemberService.class);

 //참조값이 같은 것을 확인
 System.out.println("memberService1 = " + memberService1);
 System.out.println("memberService2 = " + memberService2);

 //memberService1 == memberService2
 assertThat(memberService1).isSameAs(memberService2);

}
  • AnnotationConfigApplicationContext은 Beandefinition에서 아래와 같은정보를 가져온다
    • BeanClassName: 생성할 빈의 클래스 명(자바 설정 처럼 팩토리 역할의 빈을 사용하면 없음) factoryBeanName: 팩토리 역할의 빈을 사용할 경우 이름, 예) appConfig factoryMethodName: 빈을 생성할 팩토리 메서드 지정, 예) memberService Scope: 싱글톤(기본값) lazyInit: 스프링 컨테이너를 생성할 때 빈을 생성하는 것이 아니라, 실제 빈을 사용할 때 까지 최대한 생성을 지연처리 하는지 여부 InitMethodName: 빈을 생성하고, 의존관계를 적용한 뒤에 호출되는 초기화 메서드 명 DestroyMethodName: 빈의 생명주기가 끝나서 제거하기 직전에 호출되는 메서드 명 Constructor arguments, Properties: 의존관계 주입에서 사용한다. (자바 설정 처럼 팩토리 역할의 빈을 사용하면 없음)
  • 결과
    • 스프링 컨테이너 덕분에 고객의 요청이 올 때마다 객체를 생성하는 것이 아니라, 이미
    • 만들어진 객체를 공유해서 효율적으로 재사용할 수 있다
  • Configuration 과 싱글톤
    • 스프링 컨테이너는 싱글톤 레지스트리다. 따라서 스프링 빈이 싱글톤이 되도록 보장해주어야 한다
    • 스프링은 클래스의 바이트코드를 조작하는 라이브러리를 사용한다
    • 바로 @Configuration을 적용한 AppConfig 에있다

 

댓글