싱글톤 컨테이너
웹 애플리케이션과 싱글톤
- 트래픽이 들어왔을 때 같은 리소스를 여러 트래픽에서 호출하면 각각에 대해 객체가 생성될것이다. TPS가 커질 수록 문제가 발생한다.
- 순수 자바 코드의 경우 DI 컨테이너인 AppConfig는 요청할 때마다 객체를 새로 생성한다. 이런 경우 메모리의 낭비가 굉장히 심해진다.
- 그래서 고안된것이 싱글톤 패턴이다.
-
private static final SingletonService instance = new SingletonService();
- 그런데, 위와 같이 코드를 작성하면 어떤 문제가 발생할까? 보통 생성된 싱글톤을 호출하게 되면 .getInstance()를 쓰게 된다.
- getInstance()를 쓰게 되면 클라이언트는 구체 클래스 getInstance()에 의존하게 된다. 이는 DIP를 위반하게 되면서 자연스럽게 OCR도 위반한다.
스프링 컨테이너
- 스프링 컨테이너라고 부르거나 혹은 싱글톤 컨테이너라고 부른다. 싱글톤 객체를 생성하고 관리하는 기능을 싱글톤
레지스트리라 한다. - 스프링 컨테이너에 의해서 DIP, OCR, 테스트 (싱글톤 패턴은 테스트 하기 쉽지 않음), private 생성자부터 자유롭게 싱글톤을 사용할 수 있다.
- 아래 코드에서 스프링 컨테이너에서 각 메서드들에 대해 싱글톤으로 관리하게 된다.
-
@Test @DisplayName("스프링 컨테이너와 싱글톤") void springContainer() { ApplicationContext 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); }
- 고객의 요청에 따라 객체를 생성하는것이 아니라, 이미 만들어진 객체를 공유해서 효율적으로 재사용할 수 있게 되는 장점이 있다.
싱글톤 객체 설계
- 싱글톤 객체는 stateful 하게 설계하면 안된다. 즉, stateless 하게 설계해야 한다. 이 말은 값을 수정하면 안되고 읽기만 하도록 처리하는것이 중요하다는 의미다.
- 특히, 스프링 빈 필드에 공유 값을 설정하면 큰 장애가 발생할 수 있다.
- 이 문제를 해결하기 위해서는 자바에서 공유되지 않는 지역변수, 파라미터, ThreadLocal을 사용해야 한다.
-
public int order(String name, int price){ //this.price = price 이렇게 쓰지 말고 아래처럼 바로 리턴해라 return price; }
- 싱글톤 객체를 잘 설계했어도 같은 객체를 두개 생성하게 되면 Spring Container에서 아무리 싱글톤을 관리한다고 하지만 싱글톤이 깨지는것처럼 보이게 된다. Spring Container에서는 어떻게 이 문제를 해결하고 있을까?
- 결과부터 말하면 @Configuration 을 통해서 Spring Container에서 같은 객체에 대한 생성에 대해 AppConfig@CGLB (바이트 코드를 조작한다.) 메서드를 오버라이드해서 로직을 수행하여 같은것에 대해 한번 더 생성하지 않는다.
- 아래는 Sudo 코드이다.
-
@Bean public MemberRepository memberRepository() { if (memoryMemberRepository가 이미 스프링 컨테이너에 등록되어 있으면?) { return 스프링 컨테이너에서 찾아서 반환; } else { //스프링 컨테이너에 없으면 기존 로직을 호출해서 MemoryMemberRepository를 생성하고 스프링 컨테이너에 등록 return 반환 } }
- @Configuration을 떼면 싱글톤이 깨진다. @Bean 처리된 메서드의 호출된 객체들이 모두 생성된다고 보면 된다. (중복) 즉, @Bean만 쓰게 되면 싱글톤을 보장하지 않는다. 여기서 @Autowired 를 쓰게 되면 이 문제를 해결할 수 있는데 이미 한번 호출된것은 자동 주입해주므로써 같은 객체로 처리하게 된다.
'Spring' 카테고리의 다른 글
의존관계 자동 주입 (0) | 2021.12.13 |
---|---|
컴포넌트 스캔 (0) | 2021.12.12 |
객체 지향 원리 적용 (0) | 2021.12.10 |
Spring 예제 (0) | 2021.12.10 |
객체지향 설계와 스프링 (0) | 2021.12.09 |
댓글
이 글 공유하기
다른 글
-
의존관계 자동 주입
의존관계 자동 주입
2021.12.13 -
컴포넌트 스캔
컴포넌트 스캔
2021.12.12 -
객체 지향 원리 적용
객체 지향 원리 적용
2021.12.10 -
Spring 예제
Spring 예제
2021.12.10