애플리케이션 컨텍스트는 싱글톤 레지스트리이다.
- 오브젝트 팩토리와 비슷한 동작을 하지만, 애플리케이션 컨텍스트는 싱글톤을 보장한다.
- 하나의 오브젝트만 만들어주고, 사용자의 요청을 담당하는 여러 스레드에서 하나의 오브젝트를 동시에 공유해서 사용함을 보장한다.
DaoFactory factory = new DaoFactory();
UserDao dao1 = factory.userDao();
UserDao dao2 = factory.userDao();
System.out.println("Factory dao1 = " + dao1);
System.out.println("Factory dao2 = " + dao2);
System.out.println("Factory dao1 == dao2 = " + (dao1==dao2));
System.out.println("Factory dao1.equals(dao2) = " + (dao1.equals(dao2)));
ApplicationContext ac = new AnnotationConfigApplicationContext(DaoFactory.class);
UserDao dao3 = ac.getBean("userDao", UserDao.class);
UserDao dao4 = ac.getBean("userDao", UserDao.class);
System.out.println("ApplicationContext dao3 = " + dao3);
System.out.println("ApplicationContext dao4 = " + dao4);
System.out.println("ApplicationContext dao3 == dao4 = " + (dao3==dao4));
System.out.println("Factory dao3.equals(dao4) = " + (dao3.equals(dao4)));
싱글톤 사용법
- 클래스 밖에서는 오브젝트 생성 못하도록 생성자는 private
- 싱글톤 오브젝트를 저장할 수 있는 자신과 같은 타입의 스태틱 필드 정의
- 스태틱 팩토리 메소드인 getInstance()를 만들고, 호출되는 시점에서 한번만 오브젝트 생성되게 함
- 오브젝트 생성 이후에는 getInstance() 메소드를 통해 이미 만들어진(스태틱 필드) 오브젝트 사용
public class UserDaoSingleton {
private static UserDaoSingleton INSTANCE;
private ConnectionMaker connectionMaker;
private UserDaoSingleton(ConnectionMaker connectionMaker) {
this.connectionMaker = connectionMaker;
}
public static synchronized UserDaoSingleton getInstance() {
if(INSTANCE == null) INSTANCE = new UserDaoSingleton(???);
return INSTANCE;
}
}
싱글톤 단점
- priavte이기 때문에 상속할 수 없다.
- 테스트하기 어렵다
- 싱글톤은 초기화 과정에서 생성자 등을 통해 사용할 오브젝트를 다이나믹하게 주입이 불가능하다. 따라서 필요한 오브젝트를 직접 만들어 사용해야 한다(테스트용 오브젝트로 대체 어려움)
- 싱글톤은 전역 상태를 만들 수 있기 때문에 바람직하지 못하다.
- 싱글톤의 스태틱 메소드를 이용해 언제든지 접근할 수 있기 때문에 자연스럽게 전역상태로 사용되기 쉽다.
- 서버에서는 싱글톤이 하나만 만들어지는 것을 보장하지 못한다.
싱글톤 레지스트리
- 싱글톤 패턴의 단점 극복하기 위함
- 스태틱 메소드와 private 생성자 사용할 필요 없음
- 자유롭게 오브젝트 생성 및 테스트 가능
- 생성자 파타미터 사용 가능 등 제약이 없음
싱글톤 주의 점
- 다중 사용자의 요청을 한꺼번에 처리하는 스레드들이 동시에 싱글톤 오브젝트의 인스턴스 변수를 수정할 수 있기 때문에, 멀티스레드 환경에서 반드시 무상태(stateless) 방식으로 만들어져야 함
- stateful 방식으로 만들어져야 하는 정보는, 파라미터와 로컬 변수, 리턴값 등을 이용해야 함