DaoFactory와 스프링 IoC의 차이
DaoFactory를 직접 사용하는 것과 @Configuration 애노테이션을 추가해서 스프링의 에플리케이션 컨텍스트를 통해 사용하는 것은 테스트 결과만 보자면 동일한 것 같지만 그렇지 않다.
다음은 DaoFacotry의 userDao() 메소드를 두 번 호출해서 리턴되는 UserDao 오브젝트를 출력하는 코드이다.
public class EqualityCheck {
public static void main(String[] args) {
DaoFactory factory = new DaoFactory();
UserDao dao1 = factory.userDao();
UserDao dao2 = factory.userDao();
System.out.println(dao1);
System.out.println(dao2);
}
}
Dao1과 Dao2가 서로 다른 객체인 것을 확인할 수 있다.
이번에는 getBean() 메소드를 이용해 userDao라는 이름으로 등록된 오브젝트를 가져와 보자.
ApplicationContext context = new AnnotationConfigApplicationContext(DaoFactory.class);
UserDao dao3 = context.getBean("userDao", UserDao.class);
UserDao dao4 = context.getBean("userDao", UserDao.class);
System.out.println(dao3);
System.out.println(dao4);
동일한 오브젝트를 리턴한 것을 확인할 수 있다.
콘솔을 확인하면 다음과 같이 “Creating shared instance of singleton bean”이라고 적혀있다.
싱글톤과 싱글톤 레지스트리
- 스프링은 기본적으로 별다른 설정을 하지 않으면 내부에서 생성하는 빈 오브젝트를 모두 싱글톤(패턴)으로 만든다. 하지만 이런 싱글톤은 몇 가지 문제점이 있다.
- 애플리케이션 안에 제한된 수, 대개 한 개의 오브젝트만 만들고 이를 전역적으로 공유해서 사용하는 것
[문제점]
- private 생성자를 가지고 있기 때문에 상속할 수 없다.
- 테스트하기 힘들다.
- 싱글톤은 만들어지는 방식이 제한적이기 때문에 테스트에서 사용될 때 목 오브젝트 등으로 대체하기 힘들다.
- 서버환경에서는 싱글톤이 하나만 만들어지는 것을 보장하지 못한다.
- 서버에서 클래스 로더를 어떻게 구성하고 있느냐에 따라서 싱글톤 클래스임에도 하나 이상의 오브젝트가 만들어질 수 있다.
- 싱글톤의 사용은 전역 상태를 만들 수 있기 때문에 바람직하지 못하다.
이처럼 싱글톤 패턴 구현은 여러 가지 단점이 있기 때문에 스프링은 직접 싱글톤 형태의 오브젝트를 만들고 관리하는 기능을 제공한다. 이를 싱글톤 레지스트리라고 한다. 싱글톤 레지스트리는 스태택 메소드와 private 생성자를 사용해야 하는 비정상적인 클래스가 아니라 평범한 자바 클래스를 싱글톤으로 활용하게 해준다.
⚠️ 싱글톤과 오브젝트의 상태
싱글톤이 멀티스레드 환경에서 서비스 형태의 오브젝트로 사용되는 경우에는 상태정보를 내부에 갖고 있지 않은 무상태 방식으로 만들어져야 한다(여러 사람이 접근해서 값이 변경될 수 있음). 따라서 싱글톤은 기본적으로 인스턴스 필드의 값을 변경하고 유지하는 상태유지 방식으로 만들지 않고, 파라미터와 로컬 변수, 리턴 값등을 이용해야한다.
public class UserDao {
private ConnectionMaker connectionMaker;
private Connection c;
private User user;
public User get(String id) throws ClassNotFoundException, SQLException {}
}