// 1. static 영역에 객체를 1개만 생성해둔다.
private static final SingletonService instance = new SingletonService();
// 2. public으로 열어서 객체 인스터스가 필요하면 이 static 메서드를 통해서만 조회하도록 허용한다.
public static SingletonService getInstance() {
return instance;
}
// 3. 생성자를 private으로 선언해서 외부에서 new 키워드를 사용한 객체 생성을 못하게 막는다.
private SingletonService() {}
싱글톤 패턴을 구현하는 방법은 여러가지가 있지만,
여기선 객체를 미리 생성해두는 가장 단순하고 안전한 방법 선택
스프링 컨테이너 덕분에 트래픽이 발생할 때 마다 객체를 생성하는 것이 아니라, 이미 만들어진 객체를 공유해서 효율적으로 재사용할 수 있다.
참고: 스프링의 기본 빈 등록 방식은 싱글톤이지만, 싱글톤 방식만 지원하는 것은 아니다. 요청할 때 마다
새로운 객체를 생성해서 반환하는 기능도 제공한다. *빈 스코프
@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() {
return new MemoryMemberRepository();
}
}
위 코드를 실행해 보면 각각 다른 2개의 MemoryMemberRepository
가 생성되면서 싱글톤이 깨지는것 처럼 보이지만 같은 인스턴스가 공유되어 사용된다.
이것은 스프링이 클래스의 바이트코드를 조작하는 라이브러리를 사용해서 *CGLIB
AppConfig를 상속받은 임의의 다른 클래스를 만들고, 그 클래스를 스프링 빈으로 등록하기 때문이다.
이 클래스가 싱글톤이 보장되도록 만들어준다.
AppConfig@CGLIB 예상코드
@Bean
public MemberRepository memberRepository() {
if (memoryMemberRepository가 이미 스프링 컨테이너에 등록되어 있으면?) {
return 스프링 컨테이너에서 찾아서 반환;
} else { //스프링 컨테이너에 없으면
기존 로직을 호출해서 MemoryMemberRepository를 생성하고 스프링 컨테이너에 등록
return 반환
}
}
memberRepository()
처럼 의존관계 주입이 필요해서 메서드를 직접 호출할 때 싱글톤을 보장하지 않는다.