: 클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴
- 스프링은 태생이 기업용 온라인서비스 기술을 지원하기 위해 탄생
--> 대부분 웹 애플리케이션이며, 보통 여러 고객이 동시에 요청을 함!- 고객의 요청이 올 때 마다 새로운 객체를 생성하면?
--> 메모리 낭비 문제가 발생
--> 이를 해결하기 위한 방법이 바로싱글톤(Singelton)
패턴
- 싱글톤을 기본으로 지원하는 스프링 컨테이너를 거치지 않았기 때문에 싱글톤이 적용되지 않은 상태
- 요청이 올 때 마다 새로운 객체를 생성한다!
[ 객체 ]
- 스프링을 거치지 않고, 순수 java로 싱글톤을 적용하는 방법은 다음과 같다.
1) static영역에 객체를 딱 1개만 생성
2) 외부에서 조회할 수 있는 get메서드 생성
3) 생성자를 private로 생성해서 외부에서 new로 생성하는 것을 막는다
[ 테스트 코드 ]
isSameAs
를 통해 같은 인스턴스임을 확인!
[ 단점 ]
- 싱글톤 패턴을 구현하는 코드 자체가 많이 들어간다
--> 위처럼 static부터 이것저것..- 의존관계상 클라이언트가 구체 클래스에 의존한다
--> 어쩔 수 없이 static으로 new해서 구체를 직접 생성해야함
--> DIP 위배!- 클라이언트가 구체 클래스에 의존해서 OCP를 위반할 가능성이 높다.
- 테스트 하기가 어렵다
- 종합적으로 결국 모든 방면에서 '유연성'이 떨어진다!
- 객체를 무상태(Stateless)로 반드시 설계해야함 (치명적 오류 발생 가능!)
[ 스프링에서는? ]
- 스프링에서는 이러한 싱글톤의 모든 문제를 해결하고 싱글톤을 지원
- 기본적(default)으로 모든 객체는 싱글톤 객체
- 스프링 컨테이너는 싱글톤 컨테이너의 역할을 하며 생성, 관리를 한다
(자세한 원리는 뒤에서 설명)
[ 결과 ]
@Configuration
어노테이션이 있어야 싱글톤이 적용된다
(내부에CGLIB
를 사용하기 때문)
[ 원리 ]
- 스프링 컨테이너는 빈 설정 파일인
AppConfig
를 상속하는 임의의 클래스를 만들고 이것을 구성파일로 등록한다.
--> 왜?
구성파일에서 중복으로 사용되는 객체에 대한 코드가 모두 실행되면 중복으로 사용되는 만큼의 객체가 생성되서 싱글톤 패턴을 할 수가 없다.
: 만약 코드 그대로 실행된다면 빈이 등록될 때new memberRepository()
는 3번 실행되어 3개의 객체가 존재해야 한다!
(하지만, 실제로는 1개만 생성된다.)
--> 바로
CGLIB
라는 바이트 조작 라이브러리를 사용해 우리가 작성하는 원본AppConfig
를 상속하는 임의의 설정 파일을 만드는 것!
CGLIB
에서 어떤 처리를 하는데?
: 스프링 컨테이너에 등록된 객체면 생성 X / 없으면생성!
- 빈은 항상 무상태(Stateless)하게 설계해야 한다!
- 객체 내부에 직접 값을 저장하면 싱글톤이라서 모두 공유하게 된다.
-->지역변수
,파라미터
,ThreadLocal
등을 사용해 값을 유지해야함
- 무상태가 위반된 예시
- 더욱 자세한 내용은 빈 스코프와 함께 설명!