[토비의 스터디 3.1] 1.6 싱글톤 레지스트리와 오브젝트 스코프
2022. 5. 27. 11:14ㆍ토비의 스터디
1.5, 1.6장은 스터디에서 내가 맡은 부분이라 발표에 사용한 자료를 그대로 가져왔다.
1.6. 싱글톤 레지스트리와 오브젝트 스코프
오브젝트의 동일성(identity)과 동등성(equality)
- 동일성은 == 연산자
- 동등성은 equals() 메소드
- 동일성은 하나의 오브젝트를 두 개의 레퍼런스 변수가 가리키고 있는 상태
- 동등성은 두 개의 다른 오브젝트가 메모리상에 존재하나, 로직상의 정의에 따라 오브젝트 정보가 같다고 판단
- 스프링은 기본적으로 빈을 요청했을 때 매번 동일한 오브젝트를 돌려준다.
1.6.1. 싱글톤 레지스트리로서의 애플리케이션 컨텍스트
- 애플리케이션 컨텍스트는 싱글톤을 저장하고 관리하는 싱글톤 레지스트리다.
- 서버 애플리케이션과 싱글톤
- 스프링이 적용되는 대상은 자바 엔터프라이즈 기술을 사용하는 서버환경이다.
- 엔터프라이즈 서버환경은
- 초당 수십에서 수백 번씩 클라이언트 요청을 받아 처리할 수 있어야 한다.
- 하나의 요청을 처리하기 위해 데이터 액세스, 서비스, 비즈니스, 프레젠테이션 로직 등의 다양한 오브젝트들이 참여하는 계층형 구조이다.
- 클라이언트의 요청이 올 때마다 모든 오브젝트를 새로 생성, 제거해야 한다면 GC의 성능이 좋아져도 메모리와 성능에 가해지는 부하가 상당하다.
- 한 요청에 5개의 오브젝트가 생성되고, 초당 500개의 요청이 들어오면 한 시간동안 900만개의 오브젝트가 생성된다(5 * 500 * 3600)
- 따라서 서비스 오브젝트라는 개념을 사용한다.
- 대표적으로, 서블릿은 대부분 멀티스레드 환경에서 싱글톤으로 동작한다.
- 서블릿 클래스당 하나의 오브젝트만 생성한다.
- 사용자의 요청을 담당하는 여러 쓰레드에서 하나의 오브젝트를 공유해 사용한다.
- 애플리케이션안에서 제한된 오브젝트 수(대개 1개)만 만들어서 사용하는 것이 싱글톤 패턴의 원리이다.
- 대표적으로, 서블릿은 대부분 멀티스레드 환경에서 싱글톤으로 동작한다.
public class UserDao{
private static UserDao INSTANCE;
...
private UserDao(ConnectionMaker connectionMaker){
this.connectionMaker = connectionMaker;
}
public static synchronized UserDao getInstance(){
if(INSTANCE == null) INSTANCE = new UserDao(...);
return INSTANCE;
}
...
}
- 싱글톤 패턴의 한계
- private 생성자를 갖고 있기때문에 상속할 수 없다.
- 싱글톤은 테스트가 힘들다.
- 서버환경에서는 싱글톤이 하나만 만들어지는 것을 보장하지 못한다.
- 싱글톤의 사용은 전역 상태를 만들 수 있기 때문에 바람직하지 못하다.
- 싱글톤 레지스트리(singleton registry)
- 싱글톤 패턴의 한계를 스프링의 방식으로 해결한 것이다.
- 싱글톤 형태의 오브젝트를 만들고 관리하는 스프링 컨테이너이다.
- 싱글톤 레지스트리의 장점
- 평범한 자바 클래스를 싱글톤으로 활용 가능하다.
- static 메소드와 private 생성자를 사용할 필요 없다.
- 생성, 관계설정, 사용에 대한 제어권이 컨테이너에게 있기 때문이다.
- 테스트가 용이하다.
- 테스트 환경에 따라 자유롭게 오브젝트를 생성할 수 있다.
- 객체지향 설계 방식을 고수할 수 있다.
- 평범한 자바 클래스를 싱글톤으로 활용 가능하다.
1.6.2. 싱글톤과 오브젝트의 상태
- stateless(무상태) 방식
- 싱글톤이 멀티스레드 환경에서 사용되는 경우, 내부에 상태 정보가 없는 무상태 방식으로 만들어져야 한다.
- 그렇지 않으면 저장할 공간이 하나뿐이니 서로 값을 덮어쓰고 저장하지 않은 값을 읽어올 수 있다.
- 파라미터, 로컬 변수, 리턴 값 등은 자유롭게 이용할 수 있다.
- 지역 변수를 저장하는 Stack 영역은 각 Thread 별로 할당되지만, 전역 변수를 저장하는 Heap 영역은 Thread 간 공유된다.
- 읽기 전용의 속성을 가진 정보라면 인스턴스 변수로 사용해도 좋다.
- ex) UserDao의 ConnectionMaker는 인스턴스 변수로 선언되어 있다.
- ConnectionMaker는 스프링이 관리하는 빈이며, UserDao에서 사용하려는 빈을 저장하려는 용도이므로(변경 X, 읽기 전용) 문제되지 않는다.
public class UserDao{
private ConnectionMaker connectionMaker; // 초기에 설정 후 변하지 않는 읽기전용 인스턴스변수
private Connection c; // 매번 새로운 값으로 바뀌는 정보가 담기는 인스턴스 변수
private User user; // 사용하면 심각한 문제를 초래한다.
public User get(String id) throws ClassNotFoundException, SQL Exception{
this.c = connectionMaker.makeConnection();
...
this.user = new User();
this.user.setId(rs.getString("id"));
...
}
}
ConnectionMaker 타입의 인스턴스변수는 해당 클래스의 makeConnection() 메소드를 사용하기 위해 저장한 값일 뿐, 변경될 여지가 없으므로 사용해도 좋다.
1.6.3. 스프링 빈의 스코프
- 빈의 스코프(scope)
- 스프링이 관리하는 빈(bean) 이 생성되고, 적용되는 범위
- 기본 스코프는 싱글톤(singleton)
- 스코프의 종류
- prototype - 컨테이너에 빈을 요청할 때마다 매번 새로운 오브젝트(bean) 생성
- request - 새로운 HTTP 요청이 생길 때마다 생성됨
- session - 웹의 세션과 라이프 사이클이 거의 동일
'토비의 스터디' 카테고리의 다른 글
[토비의 스프링 3.1] 2.1 UserDaoTest 다시 보기 (0) | 2022.06.01 |
---|---|
[토비의 스프링 3.1] 1.7 의존관계 주입(DI) (0) | 2022.05.28 |
[토비의 스프링 3.1] 1.5 스프링의 IoC (0) | 2022.05.27 |
[토비의 스프링 3.1] 1.4 제어의 역전(IoC) (0) | 2022.05.26 |
[토비의 스프링 3.1] 1.3 DAO의 확장 (0) | 2022.05.25 |