티스토리 뷰
웹 애플리케이션과 싱글톤
대부분의 스프링 애플리케이션은 웹 애플리케이션. 웹 애플리케이션은 보통 여러 고객이 동시에 요청을 한다.
문제점: 클라이언트 A, B, C가 memberService를 요청할 때마다 객체를 생성한다. 위 그림에서 객체를 3개 생성하게 된다.
스프링 없는 순수한 DI 컨테이너 테스트
@Test
@DisplayName("스프링 없는 순수한 DI 컨테이너")
void pureContainer() {
AppConfig appConfig = new AppConfig();
// 1.조회: 호출할 때마다 객체를 생성
MemberService memberService1 = appConfig.memberService();
// 2.조회: 호출할 때마다 객체를 생성
MemberService memberService2 = appConfig.memberService();
// 참조값이 다름을 확인
System.out.println("memberService1 = " + memberService1);
System.out.println("memberService2 = " + memberService2);
//memberService != memberService2 확인
Assertions.assertThat(memberService1).isNotSameAs(memberService2);
}
실행 결과
싱글톤 패턴
- 클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴
- 객체 인스턴스를 2개 이상 생성하지 못하도록 막는다.
- private 생성자를 사용
test/singleton/SingletonService.java
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() { }
public void logic() {
System.out.println("싱글톤 객체 로직 호출");
}
}
private를 활용한다.
이후 이전에 작성한 test/singleton/SingletonTest.java을 아래와 같이 작성하고 실행하면
@Test
@DisplayName("싱글톤 패턴을 적용한 객체 사용")
void singletonServiceTest() {
new SingletonService();
}
실행 결과
따라서 아래와 같이 수정 후 실행
void singletonServiceTest() {
SingletonService singletonService1 = SingletonService.getInstance();
SingletonService singletonService2 = SingletonService.getInstance();
System.out.println("SingletonService1 = " + singletonService1);
System.out.println("SingletonService2 = " + singletonService2);
}
실행 결과
못믿겠다면 isSameAs로 동일한 객체인지 확인
Assertions.assertThat(singletonService1).isSameAs(singletonService2);
싱글톤 패턴을 적용하면 고객의 요청이 올 때 마다 미리 만들어진 객체를 공유해서 효율적으로 사용한다.
싱글톤 패턴 문제점
- 아래와 같은 코드가 기본적으로 들어간다. (구현하는 코드 자체가 많이 들어간다.)
private static final SingletonService instance = new SingletonService();
public static SingletonService getInstance() {
return instance;
}
private SingletonService() { }
- 클라이언트가 구체 클래스에 의존한다. DIP 위반 (클라이언트.getInstance() 등을 사용하므로)
- 클라이언트가 구체 클래스에 의존하므로 OCP 원칙을 위반할 가능성이 높다.
- 테스트하기 어렵다.
- 내수 속성을 변경하거나 초기화하기 어렵다.
- private 생성자로 자식 클래스를 만들기 어렵다.
- 결론적으로 유연성이 떨어진다.
스프링 컨테이너가 해결해줄 것이다!!!
싱글톤 컨테이너
스프링 컨테이너는 싱글톤 패턴의 문제점을 해결하면서 객체 인스턴스를 싱글톤(1개만 생성)으로 관리한다.
이전에 배운 스프링 빈이 바로 싱글톤으로 관리되는 빈이다.
- 스프링 컨테이너는 싱글톤 패턴을 적용하지 않아도, 객체 인스턴스를 싱글톤으로 관리한다.
- 스프링 컨에티너는 싱글톤 컨테이너 역할을 한다. 싱글톤 객체를 생성하고 관리하는 기능을 싱글톤 레지스트리라 한다.
- 싱글톤 패턴의 모든 단점을 해결하면서 객체를 싱글톤으로 유지할 수 있다.
- 싱글톤 패턴을 위한 지저분한 코드 X / DIP, OCP, 테스트. private로 부터 자유롭게 싱글톤 사용 가능
스프링 컨테이너를 사용하는 테스트 코드
void springContainer() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService1 = ac.getBean("memberService", MemberService.class);
MemberService memberService2 = ac.getBean("memberService", MemberService.class);
System.out.println("memberService1 = " + memberService1);
System.out.println("memberService2 = " + memberService2);
Assertions.assertThat(memberService1).isSameAs(memberService2);
}
.getBean() 함수를 사용하는구나
싱글톤 컨테이너 적용 후
스프링의 기본 빈 등록 방식은 위와 같은 싱글톤이지만, 요청할 때 마다 새로운 객체를 생성해서 반환하는 기능도 제공한다. '빈 스코프'에서 설명할 것!
[출처] 스프링 핵심 원리 - 기본편, 김영한님
'Spring' 카테고리의 다른 글
[Spring] 컴포넌트 스캔 (0) | 2022.03.29 |
---|---|
[Spring] 싱글톤 방식의 주의점 / @Configuration (0) | 2022.03.28 |
[Spring] 빈 설정 형식(xml) / 빈 설정 메타 정보 (BeanDefinition) (0) | 2022.03.26 |
[Spring] 스프링 컨테이너와 스프링 빈 (0) | 2022.03.22 |
[Spring] 관심사의 분리 (0) | 2022.03.22 |
- Total
- Today
- Yesterday
- REST
- 안드로이드
- configuration
- Singleton
- hoppy
- 소셜로그인
- C++
- 위상정렬
- Test
- IntelliJ
- dijkstra
- solid
- API
- aws
- Network
- db
- S3
- Programming
- Spring
- 자료구조
- TopologicalSort
- mybatis
- HTTP
- xml
- 알고리즘
- Java
- Android
- BeanDefinition
- codedeploy
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |